<?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>Forem: Ravern Koh</title>
    <description>The latest articles on Forem by Ravern Koh (@ravernkoh).</description>
    <link>https://forem.com/ravernkoh</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%2F55006%2Fbd83f9df-675a-4c72-9037-41774563c7ff.jpg</url>
      <title>Forem: Ravern Koh</title>
      <link>https://forem.com/ravernkoh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ravernkoh"/>
    <language>en</language>
    <item>
      <title>How directory permissions work in Linux</title>
      <dc:creator>Ravern Koh</dc:creator>
      <pubDate>Sun, 10 Mar 2019 08:51:45 +0000</pubDate>
      <link>https://forem.com/ravernkoh/how-directory-permissions-work-in-linux-2kfe</link>
      <guid>https://forem.com/ravernkoh/how-directory-permissions-work-in-linux-2kfe</guid>
      <description>&lt;p&gt;In Linux, directories can have permissions assigned to them just like files. However, while the names of each type of permission make sense for files, they don’t really make sense for directories.&lt;/p&gt;

&lt;p&gt;Take the &lt;code&gt;x&lt;/code&gt; permission for example. When set on files, it indicates their ability to be executed by the user. However, it’s not like directories can be executed, so what &lt;em&gt;does&lt;/em&gt; enabling the permission even mean?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For those who want to go directly to the source of this information, I mainly referenced &lt;a href="https://unix.stackexchange.com/questions/21251/execute-vs-read-bit-how-do-directory-permissions-in-linux-work"&gt;this post on Stack Exchange&lt;/a&gt; when writing this post.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Read
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;r&lt;/code&gt; permission allows a file to be read. However, when this permission is set on a directory, it basically means that the user is allowed to list the files within the directory.&lt;/p&gt;

&lt;p&gt;Take the following directory for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@macos demo/ # ls -l
total 0
dr--------  4 root  staff  128 Mar 10 16:29 foo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example the directory is owned by &lt;code&gt;root&lt;/code&gt;, and only &lt;code&gt;root&lt;/code&gt; is allowed to list the contents of the directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@macos demo/ # ls -l foo
total 8
-rw-r--r--  1 root  staff  16 Mar 10 16:29 bar
-rw-r--r--  1 root  staff   0 Mar  7 14:58 baz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Other users would &lt;strong&gt;not&lt;/strong&gt; be able to list the contents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ravernkoh@macos demo/ $ ls -l foo
ls: foo: Permission denied
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Write
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;w&lt;/code&gt; permission is more intuitive. When set, it allows users to modify files and directories within the directory. However, it does not allow users to create or delete files within the directory unless the &lt;code&gt;x&lt;/code&gt; permission is set too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Execute
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;x&lt;/code&gt; permission allows a user to enter the directory and access the files within the directory.&lt;/p&gt;

&lt;p&gt;Take the following example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ravernkoh@macos demo/ $ ls -l
total 0
d--x------  4 ravernkoh  staff  128 Mar  7 14:58 foo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since the &lt;code&gt;r&lt;/code&gt; permission is not set, the user would not be able to list the contents of the directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ravernkoh@macos demo/ $ ls -l foo
ls: foo: Permission denied
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, the user is still able to &lt;strong&gt;access&lt;/strong&gt; and print the contents of files within that directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ravernkoh@macos demo/ $ cat foo/bar
Hello from bar!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Sticky
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;t&lt;/code&gt; permission states that for each file and directory within the directory, only the owner can rename or delete them. This is useful in a situation where multiple users share the same directory, where setting the &lt;code&gt;t&lt;/code&gt; permission could prevent one user from changing another user’s files.&lt;/p&gt;

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

&lt;p&gt;Overall, I think the best way to think about this is to treat the directory like a file containing a list of names. If the &lt;code&gt;r&lt;/code&gt; permission is set, the user can read (and essentially list) the list of names. If the &lt;code&gt;w&lt;/code&gt; permission is set, the user can write to the contents within and perhaps (depending on whether &lt;code&gt;x&lt;/code&gt; is set) create and/or delete files. If the &lt;code&gt;x&lt;/code&gt; permission is set, the user can change the list of names itself, which would be creating and/or deleting files. The user can also &lt;code&gt;cd&lt;/code&gt; into that directory, which is akin to executing it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If I’ve mentioned anything that is inaccurate or that you disagree with, feel free to respond to this post 😀. Thanks!&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My trip to Kazan, Russia</title>
      <dc:creator>Ravern Koh</dc:creator>
      <pubDate>Sat, 26 Jan 2019 03:50:58 +0000</pubDate>
      <link>https://forem.com/ravernkoh/my-trip-to-kazan-russia-24gb</link>
      <guid>https://forem.com/ravernkoh/my-trip-to-kazan-russia-24gb</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0k60iu3l4k8elf0kjikj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0k60iu3l4k8elf0kjikj.jpg" alt="Banner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just over a month ago, I travelled to Kazan, Russia, to take part in the DigitalSkills 2018 competition. Here are some of my reflections: &lt;a href="https://ravernkoh.me/posts/digital-skills-kazan-2018/" rel="noopener noreferrer"&gt;https://ravernkoh.me/posts/digital-skills-kazan-2018/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>travel</category>
      <category>cybersecurity</category>
      <category>reflection</category>
    </item>
    <item>
      <title>Very fascinating NPM packages</title>
      <dc:creator>Ravern Koh</dc:creator>
      <pubDate>Thu, 23 Aug 2018 15:35:58 +0000</pubDate>
      <link>https://forem.com/ravernkoh/very-fascinating-npm-packages-7ib</link>
      <guid>https://forem.com/ravernkoh/very-fascinating-npm-packages-7ib</guid>
      <description>&lt;p&gt;Recently, I was browsing through NPM (what?) when I came across some really interesting and fascinating packages. Of course, I left the most interesting one to the last 😬.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/is-positive"&gt;&lt;code&gt;is-positive&lt;/code&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This was the package that initiated my deep dive into the depths of NPM's 683162 packages (it's probably more by the time I post this).&lt;/p&gt;

&lt;p&gt;As it turns out, this package does indeed return whether the argument is positive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPositive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is-positive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;isPositive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;//=&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;And that's all it does&lt;/strong&gt;. I pondered about the possible use-cases of this package, because apparently, there are many.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6jFZvIfK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/786078hzuu1ad36apz5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6jFZvIfK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/786078hzuu1ad36apz5t.png" alt="is-positive weekly downloads"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I discovered another hidden gem when looking through the &lt;code&gt;Dependents&lt;/code&gt; section that NPM provides (there were 4 of them).&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/is-not-positive"&gt;&lt;code&gt;is-not-positive&lt;/code&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This package simply does the exact opposite of what &lt;code&gt;is-positive&lt;/code&gt; does. Its description is incredibly apt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--igYRwfwc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0workjjji0alqwwsl7vl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--igYRwfwc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0workjjji0alqwwsl7vl.png" alt="is-not-positive description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/is-negative"&gt;&lt;code&gt;is-negative&lt;/code&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This being JavaScript, being non-positive probably doesn't mean being negative, so a new package had to be created to check for negativity.&lt;/p&gt;

&lt;p&gt;This package's negativity was even apparent through its weekly downloads, which are considerably less than its more radiant counterpart.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5BfahkEC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ssshl75zswiz24udxvg2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5BfahkEC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ssshl75zswiz24udxvg2.png" alt="is-negative weekly downloads"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/true"&gt;&lt;code&gt;true&lt;/code&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;This is where the &lt;code&gt;true&lt;/code&gt; fun begins. I stumbled across this quite by accident after entering a few other search queries like "&lt;code&gt;is-wrong&lt;/code&gt;" and "&lt;code&gt;woah&lt;/code&gt;". It turns out that this is actually a port of the Unix utility &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As with all Unix utilities, its usage was quite easy to grasp.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;myTrueValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;t&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="nx"&gt;myTrueValue&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="c1"&gt;// Logs 'true'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, I felt that this package looked a bit shadier than the rest due to its use of &lt;code&gt;var&lt;/code&gt;. Thus, I decided to take a look at some of the open issues on its GitHub. &lt;em&gt;You won't believe what happened next.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cPS-gq2h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0xt3elkuoy3ve3yfjo95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cPS-gq2h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0xt3elkuoy3ve3yfjo95.png" alt="true critical issue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I felt betrayed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As it turns out, there was a critical vulnerability in the code, discovered by &lt;a href="https://github.com/patrick-steele-idem"&gt;Patrick Steele-Idem&lt;/a&gt;, who spent hours tracing down the problem down.&lt;/p&gt;

&lt;p&gt;It turns out that another library had contained the following code, which caused &lt;code&gt;true&lt;/code&gt; to return &lt;code&gt;false&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luckily, he came up with a very quick fix that solved this issue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&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;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)()&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Fix it!&lt;/span&gt;
        &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Overall, (re)discovering all these wonderful packages has been a very rewarding experience for me. I will probably never do this again.&lt;/p&gt;

</description>
      <category>node</category>
      <category>npm</category>
      <category>fascinating</category>
      <category>satirical</category>
    </item>
    <item>
      <title>The database that can store the Internet</title>
      <dc:creator>Ravern Koh</dc:creator>
      <pubDate>Mon, 30 Jul 2018 07:22:51 +0000</pubDate>
      <link>https://forem.com/ravernkoh/the-database-that-can-store-the-internet-2man</link>
      <guid>https://forem.com/ravernkoh/the-database-that-can-store-the-internet-2man</guid>
      <description>&lt;p&gt;Wouldn't it be awesome if you could save the entire Internet into a database? Well, you can now do so! Infinite exploits a simple loophole in your operating system to enable you to store an infinite amount of data, without using a single byte.&lt;/p&gt;

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

&lt;p&gt;A file contains data, which is measured in bytes. If a file contains &lt;code&gt;Hello!&lt;/code&gt;, it takes up 7 bytes (remember to count the newline character). If a file contains &lt;code&gt;Bye bye~&lt;/code&gt;, it takes up 9 bytes. &lt;em&gt;Simple&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now what if a file contains nothing? How many bytes would the file take up? That's right, 0! But a file can still store data, even if it contains nothing. Where? In its &lt;em&gt;name&lt;/em&gt; of course! If we store data in its name, we can now have a file that stores data, but contains nothing, and thus takes up 0 bytes!&lt;/p&gt;

&lt;p&gt;Here, have some evidence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fravernkoh%2Finfinite%2Fmaster%2Fassets%2Fhow-it-works.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fravernkoh%2Finfinite%2Fmaster%2Fassets%2Fhow-it-works.png" alt="Evidence"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I like it!
&lt;/h2&gt;

&lt;p&gt;The source code for this project can be found &lt;a href="https://github.com/ravernkoh/infinite" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Feel free to give it a ⭐️ and use it in production 🤪!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>database</category>
      <category>satirical</category>
      <category>go</category>
    </item>
    <item>
      <title>What's the most ambitious project you have ever embarked on? Did you succeed?</title>
      <dc:creator>Ravern Koh</dc:creator>
      <pubDate>Sat, 28 Jul 2018 10:50:55 +0000</pubDate>
      <link>https://forem.com/ravernkoh/whats-the-most-ambitious-project-you-have-ever-embarked-on-did-you-succeed-3m2m</link>
      <guid>https://forem.com/ravernkoh/whats-the-most-ambitious-project-you-have-ever-embarked-on-did-you-succeed-3m2m</guid>
      <description>&lt;p&gt;Would love to hear about the most crazy, out of this world projects that may or may not have come to be 😬!&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Collaborative text editing with Logoot</title>
      <dc:creator>Ravern Koh</dc:creator>
      <pubDate>Thu, 26 Jul 2018 13:54:50 +0000</pubDate>
      <link>https://forem.com/ravernkoh/collaborative-text-editing-with-logoot-2gh0</link>
      <guid>https://forem.com/ravernkoh/collaborative-text-editing-with-logoot-2gh0</guid>
      <description>&lt;p&gt;Recently, I became intrigued with how collaborative text editing works. I was working on a school assignment in a group, and we were using Google Docs to work. It almost seems like magic, how one person can type something, and a few seconds later have it appear on others’ screens without any conflicts. I also recently discovered that the Keynote and Notes apps have collaborative features built in. So I decided to take a deep dive into collaborative text editing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with collaboration
&lt;/h2&gt;

&lt;p&gt;To edit a purely text-based document, you actually only do 2 basic operations: insert and delete. Any other operations are built on these 2 operations. A single user editing a document might look something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fh9kcjnw3sq96tv06790n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fh9kcjnw3sq96tv06790n.png" alt="Single user editing a document"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To collaborate in a document, the naive approach would be to send over each operation a user performs to all other users editing the document. This works when the connection is fast, perhaps when the users are connected in a LAN.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fn6exl8cigf8tgroe66ji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fn6exl8cigf8tgroe66ji.png" alt="2 users editing a single document over a LAN/very fast Internet connection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, when network latency becomes significant, it is incredibly easy to achieve race conditions like this one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fyuf29wg728hoy9ei0bbn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fyuf29wg728hoy9ei0bbn.png" alt="2 users editing a single document with network latency"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When these race conditions occur, the documents on both clients become out of sync, and because of the nature of these operations, it is rare that they will become in sync again. Due to this, we need a better way of structuring these operations, or even structuring the document itself, so that reliable and consistent collaborative editing becomes a reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operational Transformation
&lt;/h2&gt;

&lt;p&gt;Enter Operational Transformation, or OT for short. OT is an algorithm that will keep documents consistent across all clients, no matter the order of the operations that get sent from other clients. Wave (the collaborative engine behind Google Docs), uses OT. I didn’t dive into OT too deeply, as I found other, simpler, and more intuitive solutions that I will explain later on. But for now, here is a quick rundown on how basic OT works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick rundown
&lt;/h3&gt;

&lt;p&gt;Let’s begin by understanding the very basics of OT. As mentioned earlier, a document is simply some content, which can be operated on by either inserting or deleting. The way OT solves the issue of concurrent editing is by &lt;em&gt;transforming&lt;/em&gt; each operation using the previous operation, before it is applied to the document. Using the earlier example, after client A performs the insert on their document, client B’s delete operation, which is the next in line to be performed, gets transformed.&lt;/p&gt;

&lt;p&gt;After the transformation, we can see that the operation now deletes the correct character from the document, not the wrong one in the naive example. Also, over on client B’s document, client A’s insert operation gets transformed after client B’s delete operation is performed, and the resulting document is the same on both ends.&lt;/p&gt;

&lt;h3&gt;
  
  
  Downsides to OT
&lt;/h3&gt;

&lt;p&gt;Unfortunately, most of the popular OT algorithms are not always commutative. This means that when applying OT to two separate documents, it is not always guaranteed that they will end up being the same. Although this is rare, it can happen, and this will result in measures put into place to ensure consistency every once in a while. Thus, a different way of doing collaborative editing has surfaced in the recent years, known as CRDTs.&lt;/p&gt;

&lt;h2&gt;
  
  
  CRDTs
&lt;/h2&gt;

&lt;p&gt;There are actually 2 flavours of CRDTs. They are (bear with me) Commutative Replicated Data Type and Convergent Replicated Data Type. The following will be about the former. CRDTs take a different approach from OT, in that they rely on structuring the &lt;strong&gt;document&lt;/strong&gt; in a certain way, and not really on structuring the &lt;strong&gt;operations&lt;/strong&gt;. This means that most of the time, using the CRDT approach, the document will be stored in a different format then just a simple string. This includes using things like binary trees and special position identifiers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Downsides to CRDTs
&lt;/h3&gt;

&lt;p&gt;When using CRDTs instead of OT, we are trading time complexity for space complexity. This means that while OT will take more time to process than CRDTs, CRDTs will usually end up using significantly more memory than OT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logoot
&lt;/h2&gt;

&lt;p&gt;Logoot is a great (and simple) example of a CRDT. It is one of the easier CRDTs to understand, and extensions/variations have also been built upon it to enable extra functionality, like group undo/redo. It is the main CRDT that I will be focusing on (duh, look at the title), and also implementing it, which I will talk about in the next story.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic principles
&lt;/h3&gt;

&lt;p&gt;Going back to the original example with the race condition, you can see that the document got out of sync because the operations were using a position within the string. So when an insertion happens, everything after the inserted character is shifted to the right, which means their position is incremented.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmuig2rolgvsax5ld9iji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmuig2rolgvsax5ld9iji.png" alt="The position of the ‘c’ is incremented, from 2 to 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a second operation is applied onto both content, they are inserted at the same position, as specified in the operation. However, they occur at different characters as a result of the first operation. For example, in the next image, the original intention is to insert a ‘y’ after the ‘c’. However, due to the operation inserting in a fixed position, the ‘y’ is inserted after the ‘x’ instead.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Faksug90umvefgv4zd0c7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Faksug90umvefgv4zd0c7.png" alt="The effect of the operation is no longer as intended"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Logoot tries to solve this problem by making the positions move with the text instead. That is, it assigns unique identifiers to each character/group of characters in the document, and performs the insertions and deletions based on the position of these identifiers.&lt;/p&gt;

&lt;p&gt;In Logoot, the document is split up into groups of text. A group of text is called an &lt;code&gt;atom&lt;/code&gt;. Each atom is given a unique identifier, or a &lt;code&gt;uid&lt;/code&gt;, which has to be generated in a special way that will be covered later. Each &lt;code&gt;uid&lt;/code&gt; is comparable to other &lt;code&gt;uids&lt;/code&gt;. This means that you can do things like ask if &lt;code&gt;uid1&lt;/code&gt; &amp;lt; &lt;code&gt;uid2&lt;/code&gt; and vice versa. You can also check if they are equal. The document is then stored as an array of &lt;code&gt;(uid, atom)&lt;/code&gt; pairs, sorted by the &lt;code&gt;uids&lt;/code&gt; within the pairs in ascending&lt;br&gt;
order. There will also be two special, blank lines that exist in every document. One at the very start which will have the &lt;code&gt;MIN_uid&lt;/code&gt;, and at the very bottom, which will have the &lt;code&gt;MAX_uid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Phew, that was a lot to take in. Here comes the most important part though. &lt;em&gt;For any two different &lt;code&gt;uids&lt;/code&gt;, you should always be able to find a &lt;code&gt;uid&lt;/code&gt; in between them.&lt;/em&gt; &lt;em&gt;This is the property that makes Logoot work.&lt;/em&gt; So, the &lt;code&gt;uids&lt;/code&gt; in Logoot need to be represented in a way that adheres to the property.&lt;/p&gt;

&lt;h3&gt;
  
  
  Representing uids
&lt;/h3&gt;

&lt;p&gt;Let’s start simple. This whole time, we represented the identifiers of each character with its position in the initial string — an integer. However, using integers as &lt;code&gt;uids&lt;/code&gt; does not adhere to the property we mentioned. Let’s say we have the &lt;code&gt;uids&lt;/code&gt; 4 and 5. It is impossible to find a integer in between 4 and 5, and thus integers cannot be used as &lt;code&gt;uids&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At this point, you might be thinking, what about floats? Now, theoretically, using real numbers as &lt;code&gt;uids&lt;/code&gt; would work, as there are an infinite number of real numbers between any two different real numbers. However, in the context of a computer, this isn’t possible. Floating point numbers are simply approximations of real numbers, which means that it’s not always possible to find a floating point number between any two floating point numbers. Simply put, &lt;em&gt;you cannot represent an infinite number of floating point numbers in just 32 or 64-bits&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So how &lt;em&gt;are&lt;/em&gt; these &lt;code&gt;uids&lt;/code&gt; represented? The answer is &lt;em&gt;lists&lt;/em&gt;. Using lists, we can easily adhere to the property. A &lt;code&gt;uid&lt;/code&gt; is represented by a list of integers. Let’s say we have the &lt;code&gt;uids&lt;/code&gt; &lt;code&gt;[4]&lt;/code&gt; and &lt;code&gt;[5]&lt;/code&gt; (Take note that these are lists of a single integer element, and not just the integers). In order to find a &lt;code&gt;uid&lt;/code&gt; in between &lt;code&gt;[4]&lt;/code&gt; and &lt;code&gt;[5]&lt;/code&gt;, since there is no integer in between &lt;code&gt;[4]&lt;/code&gt; and &lt;code&gt;[5]&lt;/code&gt;, we can simply make a longer list, that starts with a &lt;code&gt;4&lt;/code&gt; (e.g. &lt;code&gt;[4, 8]&lt;/code&gt;). Now, we have the &lt;code&gt;uids&lt;/code&gt; &lt;code&gt;[4]&lt;/code&gt;, &lt;code&gt;[4, 8]&lt;/code&gt; and &lt;code&gt;[5]&lt;/code&gt;. And this can repeat forever, since lists are infinitely extensible (Of course, the maximum size of a list is limited by the available RAM, but this is big enough that we don’t have to worry.&lt;/p&gt;

&lt;p&gt;Therefore, in Logoot, &lt;code&gt;uids&lt;/code&gt; are represented by lists of integers. &lt;em&gt;Take note that there are some additional components that make up a &lt;code&gt;uid&lt;/code&gt;, _but for the sake of&lt;br&gt;
understanding Logoot they aren’t necessary.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that we have covered &lt;code&gt;uids&lt;/code&gt; in Logoot, we can move on the constructing a simple Logoot document.&lt;/p&gt;

&lt;h3&gt;
  
  
  A sample document
&lt;/h3&gt;

&lt;p&gt;In Logoot, a document is made up of an array of &lt;code&gt;pairs&lt;/code&gt;. Each &lt;code&gt;pair&lt;/code&gt; containing a &lt;code&gt;uid&lt;/code&gt;, and an &lt;code&gt;atom&lt;/code&gt;. An &lt;code&gt;atom&lt;/code&gt; is simply a string, containing some of the content in the document. The &lt;code&gt;pairs&lt;/code&gt; in the document are always sorted by their &lt;code&gt;uids&lt;/code&gt;. To get the content of the entire document, simply concatenate all the &lt;code&gt;atoms&lt;/code&gt; in order. As with all data structures (remember Logoot is a CRDT), some operations can be performed on it.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;insert&lt;/code&gt; operation can be performed on a Logoot document. To perform an &lt;code&gt;insert&lt;/code&gt;, you simply need to have the &lt;code&gt;pair&lt;/code&gt; to insert. To generate the &lt;code&gt;uid&lt;/code&gt; for the &lt;code&gt;pair&lt;/code&gt;, you simply have to take two existing &lt;code&gt;uids&lt;/code&gt; and generate a random &lt;code&gt;uid&lt;/code&gt; in between them.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;delete&lt;/code&gt; operation can also be performed. To perform a &lt;code&gt;deletion&lt;/code&gt;, you only need to know the &lt;code&gt;uid&lt;/code&gt; to delete.&lt;/p&gt;

&lt;h3&gt;
  
  
  Start and end lines
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;insert&lt;/code&gt; operation, you can see that to generate a new &lt;code&gt;uid&lt;/code&gt;, you need 2 existing &lt;code&gt;uids&lt;/code&gt;. However, in a blank document, how would the two existing &lt;code&gt;uids&lt;/code&gt; be found? This is where the start and end lines come into play. The start and end lines are two lines that &lt;em&gt;always&lt;/em&gt; exist in a Logoot document. They contain an empty &lt;code&gt;atom&lt;/code&gt; and their &lt;code&gt;uids&lt;/code&gt; are &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;MAX&lt;/code&gt; respectively, where &lt;code&gt;MAX&lt;/code&gt; is the maximum size of an integer.&lt;/p&gt;

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

&lt;p&gt;Hopefully this article has given you a good understanding of Logoot, and even just collaborative editing in general. I &lt;a href="https://github.com/ravernkoh/logoot" rel="noopener noreferrer"&gt;implemented Logoot&lt;/a&gt; in the Go programming language. Check it out here. Be sure to check out my other stories and thanks for reading!&lt;/p&gt;

</description>
      <category>crdt</category>
      <category>logoot</category>
      <category>collaborativeediting</category>
    </item>
  </channel>
</rss>
