<?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: Brian Onang'o</title>
    <description>The latest articles on DEV Community by Brian Onang'o (@surgbc).</description>
    <link>https://dev.to/surgbc</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%2F58120%2F3a9977de-4233-40e8-b09f-f040d7f2ffab.png</url>
      <title>DEV Community: Brian Onang'o</title>
      <link>https://dev.to/surgbc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/surgbc"/>
    <language>en</language>
    <item>
      <title>Scaling Fixed Robots Using Brian Mechanisms</title>
      <dc:creator>Brian Onang'o</dc:creator>
      <pubDate>Mon, 01 Aug 2022 12:57:11 +0000</pubDate>
      <link>https://dev.to/surgbc/scaling-fixed-robots-using-brian-mechanisms-1og1</link>
      <guid>https://dev.to/surgbc/scaling-fixed-robots-using-brian-mechanisms-1og1</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/-NHHuo9FuA4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This article is about a new class of mechanisms called Brian Mechanisms. For progress on the work of building the worlds cheapest robots using Brian Mechanisms, read &lt;a href="https://dev.to/surgbc/brian-mechanism-building-the-worlds-cheapest-large-scale-agricultural-robot-49jb"&gt;the articles here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;In the search for an affordable and scalable design of an agricultural robot, the design has been established of a mechanism for turning both fixed as well as mobile robots into compound robots, thereby (1) scaling up fixed robots and (2) increasing the precision of mobile robots, as well as (3) reducing the complexity currently involved in the positioning systems of mobile robots. The new mechanism, called Brian Mechanism, can be used to build robots for the agricultural and construction industrial which don't require high precision. But it is also theoretically possible to build large scale cartesian robots for use in 3D printers, laser cutters and other application that require high precision. It is left to the imagination of the creative and inventive minds to conceive many other uses for the mechanism.&lt;/p&gt;

&lt;p&gt;Based on the degree of mobility, robots are traditionally classified into two classes: (1) fixed robots and (2) mobile robot. Fixed robots do not move with respect to certain components in their environment while mobile robots travel in their environments by using various means of locomotion. But there is yet another new class of robots called compound robots. Compound robots integrates the functions of a mobile robot and a fixed robot. Fixed robots mainly replace the functions of human arms and hands; while mobile robots, namely, replace the walking functions of human legs and feet. The compound robot uses both hands and feet, combining two functions. This way it has, with a few trade-offs here and there, the advantages of fixed robots as well as those of mobile robots.&lt;/p&gt;

&lt;p&gt;Fixed robots are mainly designed for high endurance, speed, and precision, while mobile robots are bulit for scalability. By scale we mean not the number of robot working together, but rather the size of its workspace. Combining the two we get the precision of fixed robots as well as the workspace scalability of mobile robots into our compound robots.&lt;/p&gt;

&lt;p&gt;Mobile robots can also be grouped into two categories: guided (AGVs) and autonomous(AMRs). AGVs rely on guidance devices that allow them to travel a pre-defined navigation route in relatively controlled space, while AMRs are capable of navigating an uncontrolled environment without the need for physical or electro-mechanical guidance devices. The components of a mobile robot are a controller, sensors, actuators and power system. The sensor systems required for AMRs such as self driving cars are quite complicated and therefore quite expensive. AGVs have far less complicated sensor systems while fixed robots can work without position feedback sensors since a number of them are cable of being controlled by open loop systems.&lt;/p&gt;

&lt;p&gt;Brian mechanisms, to a large degree take away the need for guidance systems for AGVs as well as the complicated sensor systems for AMRs while increasing the area over which fixed robots can work. The result is a means which, it is suggested, provides the &lt;strong&gt;cheapest&lt;/strong&gt; means of producing &lt;strong&gt;large scale robots&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concept
&lt;/h2&gt;

&lt;p&gt;The Brian Mechanism concept is this: a fixed robot carries a mobile robot. The workspace/environment of the fixed robot is the mobile robot while that of the mobile robot is the world. When the fixed robot needs to work an area greater than its workspace, the mobile robot carries it to the area adjacent to its current workspace of the same size as its current workspace. The mobile robot moves over a fixed distance each time. The motion and position of the fixed robot does not depend upon that of the mobile robot. That is, the position of the fixed robot is only a function of that of the mobile robot in as far as the position of its workspace is determined by the mobile robot. For instance, the position in the y direction can be calculated as:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;y=n∗L−yf
 y = n*L - yf
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;L&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;br&gt;
Where&lt;br&gt;
&lt;em&gt;n&lt;/em&gt; is the number of times the mobile robot has moved.&lt;br&gt;
&lt;em&gt;L&lt;/em&gt; is the distance by which the mobile robot moves&lt;br&gt;
&lt;em&gt;yf&lt;/em&gt; is the position of the fixed robot end effector in its workspace.
&lt;h2&gt;
  
  
  Comparison with Wheels and Walking Mechanisms
&lt;/h2&gt;

&lt;p&gt;Brian Mechanisms can be made from wheels, tracks or legs. Therefore it is easy to confuse them with any of these, especially with walking mechanisms. But the difference lies in the way in which the fixed robot/payload is moved. When using wheels or tracks, the displacement of the payload is equal to that of wheel axles. For example, a person sitting in a car has the same displacement from some location as that of the wheel axles. If the tires spin and the vehicles does not move, the person also does not move. That is:&lt;br&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;Sp=Sw
 Sp = Sw
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;Sp&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;Sw&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;br&gt;
Where&lt;br&gt;
Sp - is the displacement of the payload and&lt;br&gt;
Sw - is the displacement of the wheel axel.

&lt;p&gt;The same is true for tracks. Walking mechanisms also have the displacement of their payloads equal to the amount by which the joint of the leg to the payload has been displaced.&lt;/p&gt;

&lt;p&gt;But its different in Brian Mechanisms. The position of a person walking in a car from a point of reference outside the car depends not entirely on the posision of the car. This is the case in Brian Mechanisms.&lt;/p&gt;

&lt;p&gt;But there is another difference. A car's position is continuous making it, as has been mentioned under AGVs difficult to locate. The position of the mobile part of Brian Mechanisms is moved by discrete steps as opposed to the continuous displacement of the car. At any point t:&lt;br&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;ym=n∗L
 ym = n*L
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;y&lt;/span&gt;&lt;span class="mord mathnormal"&gt;m&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;This is the mechanism provided by the mechanism for locating the mobile robot in its environment. While not entirely eliminating errors, it reduces the error significantly compared to normal wheels or tracks.&lt;/p&gt;

&lt;p&gt;In summary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mobile robot part of Brian mechanisms have discrete position while normal mobile  robots have continuous positions.&lt;/li&gt;
&lt;li&gt; The position of the payload of Brian mechanisms is only partially dependent on the position of the mobile robot part. This point is capture in point 1 above.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A Practical example
&lt;/h2&gt;

&lt;p&gt;The video shows an implementations of the Brian Mechanism using a chain driven mechanism.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/yQ6trrutuZY?start=657"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>brianmechanism</category>
    </item>
    <item>
      <title>Brian Mechanism - What it is</title>
      <dc:creator>Brian Onang'o</dc:creator>
      <pubDate>Mon, 25 Jul 2022 20:12:00 +0000</pubDate>
      <link>https://dev.to/surgbc/brian-mechanism-what-it-is-5hch</link>
      <guid>https://dev.to/surgbc/brian-mechanism-what-it-is-5hch</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/yQ6trrutuZY?start=657"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Brian Mechanisms are a class of mechanisms that are functionally intended to convert fixed robots into compound robots so that they can be used to economically make cheap scalable robots. &lt;/p&gt;

&lt;p&gt;Brian mechanisms have a fixed robot part and a compound robot part. The fixed robot is carried on a platform which is carried either by a set of legs or wheels. The fixed robot can be anything from a CNC to agricultural machines.&lt;/p&gt;

&lt;p&gt;The concept is this: a fixed robot's price is reduced by making it smaller. Then a relatively cheaply priced system is used to move that fixed robot precisely over the area it is intended to work in. This forms a compound robot. The advantages of the fixed robot are inherited by the compound robot.&lt;/p&gt;

&lt;p&gt;The compound robot moves the datum used by the fixed robot to detemine the position of its end effector. By this means the workspace of the fixed robot is moved from one place to the next adjacent area. Also provided by the compound robot is a a means of having the fixed robot being able to access the whole of that new workspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difference with Walking Mechanisms and Wheels
&lt;/h2&gt;

&lt;p&gt;Brian mechanisms differ from wheels and walking mechanisms in the way in which the payload is moved. In systems having wheels or legs, motion is achieved due to the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A torque &lt;code&gt;T&lt;/code&gt; is applied by the engine to the wheel. &lt;/li&gt;
&lt;li&gt;The force on the circumference of the wheel at the point of contact with the ground due to that torque &lt;code&gt;T/r&lt;/code&gt; is less than the static Friction &lt;code&gt;Fr&lt;/code&gt; and there is a forward reaction on the wheel which causes it to move forward as it rolls. As the wheel rolls forward, its axle is translated forward. Since the axle carries the payload, the payload is also moved forward. The same applied to walking mechanisms. The force applied to the legs on the ground cause a reaction force that  move the legs and the payload forward. In brief, wheeled systems and walking mechanisms move relative to the ground.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But there is a different class of mechanisms called Brian Mechanisms which work in the following way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The payload moves relative to a platform, as opposed to relative to the ground as when using wheels.&lt;/li&gt;
&lt;li&gt;A system of legs/wheels are used to move, relative to the ground, the frame on which the platform moves so that the platform can have continuous motion.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This video illustrates some examples of Brian Mechanisms&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zpdy7t51o8g"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>robotics</category>
      <category>brianmechanism</category>
    </item>
    <item>
      <title>Brian Mechanism - Design for Affordability and Scalability</title>
      <dc:creator>Brian Onang'o</dc:creator>
      <pubDate>Sun, 24 Jul 2022 20:38:00 +0000</pubDate>
      <link>https://dev.to/surgbc/brian-mechanism-design-for-affordability-and-scalability-29p5</link>
      <guid>https://dev.to/surgbc/brian-mechanism-design-for-affordability-and-scalability-29p5</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/-NHHuo9FuA4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We have been building what should be the world's cheapest agricultural robot. The design that has been established for its platform should have use in several other areas, including: construction and manufacturing.&lt;/p&gt;

&lt;p&gt;The chief requirements for our robot are (1) that it be rightly prized to be afforded by the people that need it most. The big farmers, while this should be useful to them as well, already have other machines that they can rely on. (2) That is be scalable. By scalable we mean that it can be used on small as well as large farms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Cost&lt;/strong&gt;&lt;br&gt;
Most precision machines fall into the class that is classified as fixed robots. These have a fixed table and some means of controlling an end effector to achieve some translations or rotations on a number of axes. The end effector moves relative to the table. Its position is determined relative to some datum on the base. An inversion of this arrangement is also possible where the end effector is fixed on some axes and it is the table that moves instead along or about these axes. &lt;/p&gt;

&lt;p&gt;To achieve high precision and accuracy, fixed robots require:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Highly machined frames&lt;/li&gt;
&lt;li&gt;Actuators that can be accurately controlled.&lt;/li&gt;
&lt;li&gt;Optionally, a closed loop control system. Open loop control systems using stepper motors have been used in 3D printers with good success.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But many of these fixed robots, even when they are small in size are quite expensive. This is the reason why such places as GearBox exists where you go and pay to use even the simplest of machines. If the cost of these machines could be brought down, even if it be at the cost of a reasonable sacrifice of precision and other quality parameters, they would help spur creativity and greater invention. It is for this that we are designing.&lt;/p&gt;

&lt;p&gt;These machines are expensive for a large number of reasons. Of interest to us are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choice of material. This is the case for instance with Farmbot which uses expensive aluminum for its frame when agricultural work does not require the precision of accurately machined aluminum. &lt;strong&gt;&lt;em&gt;The solution for this is to use a composite frame&lt;/em&gt;&lt;/strong&gt; consisting of aluminum and other cheaper material. Steel for instance, may be heavier, but it is readily available and more cheaply prized.&lt;/li&gt;
&lt;li&gt;Superflous material. Some robots use more material than they need. Again in the case of farmbot, it uses more aluminum that it needs for its rail and gantry. The rail of farmbot max was entirely an aluminum V-slot. Its structural integrity is not sacrificed by doing away with some of the aluminum. It is possible to reduce that expensive material by as much as half. &lt;/li&gt;
&lt;li&gt;Big sizes. When a machine is intended to work over some size of workspace, it is built to cover all that area. The advantages of a compound robot are hardly ever in mind.&lt;/li&gt;
&lt;li&gt;Place of manufacture and intended market. Machines designed and made for the western markets are always too expensive for us. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now here are the solutions:&lt;br&gt;
i. Local design and fabrication. Here is the most obvious means of reducing the cost of these robots. For here they will find less prized technical as well as non-technical skill reducing thus their production costs. The production costs do not depend alone upon the cost of manufacture, but also on the costs incurred in the design phase. The faster we begin designing and producing our robots ourselves, the sooner we will be having them in our farms.&lt;br&gt;
ii. Expensive accurately machined material for the frame for the axes for &lt;strong&gt;cartesian coordinate robots&lt;/strong&gt; can be greatly reduced. This is accomplshed by the following steps: (i) The cross-slide carried by the frame has its length increased to &lt;code&gt;Lc&lt;/code&gt;. There is a minimun length of frame that can support the cross-slide. This length is &lt;code&gt;Lf&lt;/code&gt;. (ii) The frame is broken into sections of &lt;code&gt;Lf&lt;/code&gt; in length and spaced &lt;code&gt;Lc - Lf&lt;/code&gt; apart.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Cyan&lt;/code&gt; in the image represents &lt;code&gt;Lc&lt;/code&gt; while the &lt;code&gt;Red&lt;/code&gt; represents &lt;code&gt;Lf&lt;/code&gt;. The &lt;code&gt;Black&lt;/code&gt; reprensents a less expensive material.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtnoe2m851m402ne9qlm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtnoe2m851m402ne9qlm.png" alt="Image description"&gt;&lt;/a&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthqr77ldejo4hbkydu2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthqr77ldejo4hbkydu2c.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see it in action &lt;a href="https://www.youtube.com/watch?v=Hq0gajUEf0E" rel="noopener noreferrer"&gt;here on youtube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The total length of expensive material now needed for the frame is: &lt;code&gt;nLf&lt;/code&gt; for a length of frame equal to &lt;code&gt;nLc - Lf&lt;/code&gt;. The total saving is equal to:&lt;br&gt;


&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;n(Lc−Lf)−Lf
 n(Lc - Lf) - Lf
&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;L&lt;/span&gt;&lt;span class="mord mathnormal"&gt;c&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;L&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;L&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;br&gt;
The greater &lt;code&gt;Lc&lt;/code&gt; is the greater the savings are. Make it as great as the load will allow.

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rhqp673ednuvos3zk8f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rhqp673ednuvos3zk8f.png" alt="Percentage Savings"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feerjh1kbdsfrlw40hd3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feerjh1kbdsfrlw40hd3z.png" alt="Percentage Savings"&gt;&lt;/a&gt;&lt;br&gt;
This answers to the problem of superfluous material as well as choice of material. The places where the expensive material has been removed can be supplied with a less expensive material, represented by &lt;code&gt;black&lt;/code&gt; in the image.&lt;/p&gt;

&lt;p&gt;iii. Reducing the size of the robot and making it scalable by turning it into a compound robot as discussed in the next section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Scalability&lt;/strong&gt;&lt;br&gt;
The obvious way to make a fixed robot work over an area greater than its workspace is to place it on wheels, or on legs using any walking mechanism. But the wheel was designed for moving its payload from one place to another with very low precision. It was not designed for precision robotics. &lt;/p&gt;

&lt;p&gt;Wheels slip when the axle is translated by a value not equal to that moved by the circumference of the wheel. For example when stopping a moving wheel, the wheel becomes locked and does not rotate, but it will move for some distance before it stops. Equally when a wheel accelerates very fast, it generates a force that may overcome static friction so that it spins. The coefficient of friction between the surface and the wheel is also not constant, making control difficult.&lt;/p&gt;

&lt;p&gt;The wheel has the advantages of (1) speed, (2) energy efficiency since it does not move the payload vertically relative to the ground as some walking mechanisms do (3) scale: a wheel can go anywhere, unlike fixed robots. But due to slip, it does dismally on precision. So there have to be very complex control systems to correct the errors in its displacement if it has to be used in a precision robot. These control systems have within them equally complex sensor systems which go by such names as "sensor fusion", LIDAR, GPS, etc. Open loop control systems cannot be used here. This means that in robotics, wheeled systems are expensive if used in precision robots.&lt;/p&gt;

&lt;p&gt;Grouping robots into categories based on their mobility we have (1) fixed robots and (2) mobile robots. But the wheel, its advantages and disadvantages, is a model of the mobile robot since for the most part the mobility of a robot is achieved by putting it on wheels. Fixed robots on the other hand use a rigid structure to constrain the payload (on an end effector) to achieve the desired precision. The rigid structure is a highly and precisely machined material such as heavy thick steel or aluminium. But such materials do not come cheap. It is therefore economically impossible to scale a fixed robot to a reasonable size for several outdoor applications, such as for agriculture. The case of the &lt;a href="https://farm.bot/blogs/news/putting-farmbot-genesis-max-and-express-max-on-hold" rel="noopener noreferrer"&gt;signal failure of Farmbot Max&lt;/a&gt; illustrates this well. Although cable systems may be obtained at a cheaper material cost so that they can cover a larger workspace, they also have a limit beyond which they cannot be extended.&lt;/p&gt;

&lt;p&gt;Listed, the following are the advantages and disadvantages of mobile robots on wheels:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Advantages&lt;/th&gt;
&lt;th&gt;Disadvantages&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scalable. &lt;em&gt;Wheels can go anywhere&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;Low precision&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High speed, &lt;em&gt;compared to walking mechanisms&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;Complex control systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simple design&lt;/td&gt;
&lt;td&gt;Very expensive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a fixed robot we have:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Advantages&lt;/th&gt;
&lt;th&gt;Disadvantages&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;High precision&lt;/td&gt;
&lt;td&gt;Not scalable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open loop control possible&lt;/td&gt;
&lt;td&gt;Unreasonably small scale for agricultural applications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Affordable when small in size&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;The solution then is to design a compound robot. This way we have the  precision of fixed robots and avoid the costs associated with mobile robots. But since the fixed robot is already in place, the design work is reduced to that of a means of moving that rigid frame of a fixed robot from precisely one point of reference to another. &lt;/p&gt;

&lt;p&gt;The small difference between this compound robot and a mobile robot is in the way the legs are moved in relation to the motion of the payload. In mobile robots continuous motion of the payload requires continuous motion of the actuating system which can be some set of legs or wheels. It is the motion of the actuating system that results in the displacement of the payload.&lt;/p&gt;

&lt;p&gt;However, in the compound robot, there is no relation between the motion of the payload and the legs. For instance, continuous motion of the payload is accompanied by intermittent motion of the legs. This means that unlike in mobile robots where slip can occur at any time, in compound robots there is no slip when the robot is moving from one small workspace to the next. If a means can be devised for grounding the fixed robot frame down hard enough to overcome any slip that may be created when working, then the slip problem will have been solved. The frame can be grounded during its rest periods.&lt;/p&gt;

&lt;p&gt;Some suggestions for mechanisms for turning a fixed robot into a compound robot are available &lt;a href="https://github.com/brianmechanism/models" rel="noopener noreferrer"&gt;here on github&lt;/a&gt; &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsv8r3f1w4x8es2knoslz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsv8r3f1w4x8es2knoslz.png" alt="Brian Mechanism"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2k8po51vpxtglcfa3mdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2k8po51vpxtglcfa3mdk.png" alt="Brian Mechanism 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These suggestions are a class of mechanisms easy to be confused with walking mechanisms, but they are not walking mechanisms. They are a class of mechanisms which we have named &lt;em&gt;Brian Mechanism&lt;/em&gt;. The difference between the two is discussed in &lt;a href="https://dev.to/surgbc/brian-mechanism-what-it-is-5hch"&gt;Brian Mechanism - What it is&lt;/a&gt;&lt;/p&gt;

</description>
      <category>robotics</category>
      <category>brianmechanism</category>
    </item>
    <item>
      <title>Brian Mechanism: Building the World's Cheapest Large Scale Agricultural Robot</title>
      <dc:creator>Brian Onang'o</dc:creator>
      <pubDate>Fri, 15 Jul 2022 13:54:00 +0000</pubDate>
      <link>https://dev.to/surgbc/brian-mechanism-building-the-worlds-cheapest-large-scale-agricultural-robot-49jb</link>
      <guid>https://dev.to/surgbc/brian-mechanism-building-the-worlds-cheapest-large-scale-agricultural-robot-49jb</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/-NHHuo9FuA4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is our attempt at building the world's cheapest large scale agricultural robot.&lt;/p&gt;

&lt;p&gt;A week ago on Friday July 8, 2022 we wrote a series of articles on &lt;a href="https://dev.to/surgbc/chainbrake-building-the-worlds-cheapest-agricultural-robot-15kk"&gt;Chainbrake&lt;/a&gt;, the design that we had for our years long challenge of creating the world's cheapest agricultural robot. After several years of back and forth with our designs, we had thought that we had developed the best design in &lt;a href="https://chainbrake.github.io/"&gt;the chainbrake design&lt;/a&gt;. But a day of testing a prototype immediately revealed the problems that would be experienced with the proposed cable system. Much of what chainbrake really is now remains in our sketch books and in our heads. Although it is a good design and innovation that we hope will find use somewhere in the future, we have in the course of the week been able to come up with the design of a 2DoF Rail enabling infinite precise motion in 2 axes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our Inspiration&lt;/strong&gt;&lt;br&gt;
The inspiration for our project came from &lt;a href="https://farm.bot"&gt;FarmBot&lt;/a&gt;. Farmbot seems to us a noble attempt to create a robot to help in agricultural work, not for the big industrial farms, but for the small scale kitchen gardeners. Without their work, we would probably never have begun our work. Theirs is the spark of light that we needed to see to begin what has now been about 5 years of work in RnD. It is true that this is probably a lot of time. But the design experience we have gained in the process has led to what we have chosen to call the &lt;em&gt;Brian Mechanism&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem Defined&lt;/strong&gt;&lt;br&gt;
Our primary problem and quarrel with Farmbot is in its cost and inscalability. Farmbot is so prohibitively priced for us who live in Africa. This can be seen from its buyer distribution map. After 6 years of production, and boasting of customers in over 90 countries, hardly any of these is from Africa and the other poor regions of the world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ByMhCU-P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gy4plghda4czo3458su8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ByMhCU-P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gy4plghda4czo3458su8.jpg" alt="Farmbot Buyer Distribution Map" width="880" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://farm.bot/blogs/news/putting-farmbot-genesis-max-and-express-max-on-hold"&gt;failure of Farmbot Max&lt;/a&gt;, the largest farmbot developed by FarmBot well illustrates its inscalability.&lt;/p&gt;

&lt;p&gt;The table belows gives a comparison of the cost and size of the different farmbots available.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This leaves us with a robot we would like to have, but is too expensive for us, and which even if we would be able to afford, would still leave us disappointed that it can but work a very small area which can easily be worked by hand.&lt;/p&gt;

&lt;p&gt;But seeing as this is not an article on the many disadvantages of Farmbot, especially to the poor African farmer, we proceed to consider:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Brief Background&lt;/strong&gt;&lt;br&gt;
In the search for a design which would make an affordable and scalable robot, we have gone through several design iterations. Some of these are now relics in our sketchbooks, but considerable work has been done in some. These are some of the designs that we proposed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;A cable driven robot&lt;/em&gt;. This was dropped because of its complexity both in the mechanism and control. The name we gave for it was csybot (Circuits and Systems roBot). &lt;a href="https://github.com/brianmechanism/models/tree/master/csybot"&gt;Mathematical models on github&lt;/a&gt; and &lt;a href="https://youtu.be/4DrWVNgNWCc"&gt;an illustration on youtube&lt;/a&gt; are available.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f3kyWR0m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/88b9nh7yl9ctqm70w215.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f3kyWR0m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/88b9nh7yl9ctqm70w215.png" alt="Csybot Illustration" width="880" height="646"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Several other designs. Some have been lost while some are available &lt;a href="https://www.youtube.com/watch?v=2C6HqIM0224&amp;amp;t=314s&amp;amp;ab_channel=CSECO"&gt;on youtube&lt;/a&gt; and &lt;br&gt;
&lt;a href="https://github.com/angelRobotics/matModels"&gt;on github&lt;/a&gt; With these designs we managed to come up with the design of a platform that can achieve continuous linear motion along one axis from the intermittent motion of two legs.&lt;em&gt;But we had no way of raising up the legs to clear the ground when moving&lt;/em&gt; At this stage we were happy to rename our project to &lt;em&gt;angel robotics.&lt;/em&gt; But since some people were already using that name, we decided to change to chainbrake in the next stage.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VrmUGWSW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cw99jf2znnsbioqre6cc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VrmUGWSW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cw99jf2znnsbioqre6cc.png" alt="AngelBot Mechanism" width="726" height="588"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://chainbrake.github.io/"&gt;Chainbrake&lt;/a&gt;. This is yet another rope system. It is a low precision one, but capable of doing agricultural work. But it has been dropped because of the difficulty in tensioning rope systems. Chain brake simply means that it is a braking system for a rope system using an ordinary chain. When you insert a cable through a chain, then stretch the chain, the bearings of the chain grip on the cable so hard that it provides a way for stopping any movement of the chain.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PY07jkWv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9gafd381wg0k8zxnnkp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PY07jkWv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l9gafd381wg0k8zxnnkp.png" alt="Chainbrake concept" width="822" height="416"&gt;&lt;/a&gt; &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vEmRHyPk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zvs7lqc722wne4bpnbgh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vEmRHyPk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zvs7lqc722wne4bpnbgh.png" alt="Chainbrake actuator concept" width="880" height="737"&gt;&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We have also been able to do a little work, now on hold, on a farmbot simulator, which we discussed on &lt;a href="https://forum.farmbot.org/t/farmbot-simulator-requirements/7144?u=surgbc"&gt;the farmbot forum&lt;/a&gt;. See an illustration of it &lt;a href="https://youtu.be/rok1GQB_Lsg"&gt;on youtube&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We managed to create what is to us an interesting mechanism which combines the braking and actuation systems of the chain into a single one using two motors and a single chain. It lives in our sketchbooks. We do not want to be distracted by it now for the want of time. We hope it finds use somewhere in future. &lt;/p&gt;

&lt;p&gt;This is our problem: We need for our friends, neighbours and relatives a large scale agricultural robot that they can afford. If you already have developed such or know of one, we would be glad to hear from you so that we can immediately stop this our project. Except that ours is to be the cheapest. If there is already a cheap agricultural machine out there, we must reiterate until ours is the cheapest. But we believe that we already have a working design in: &lt;em&gt;Brian Mechanism&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As we have seen that our aim is to solve the dual problem of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Affordability&lt;/li&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;let us go on to see the steps through which we have been able to achieve this in &lt;a href="https://dev.to/surgbc/brian-mechanism-design-for-affordability-and-scalability-29p5"&gt;designing for affordability and scalability&lt;/a&gt;&lt;/p&gt;

</description>
      <category>robotics</category>
      <category>brianmechanism</category>
    </item>
    <item>
      <title>ChainBrake: Building the world's cheapest Agricultural Robot</title>
      <dc:creator>Brian Onang'o</dc:creator>
      <pubDate>Fri, 08 Jul 2022 13:47:00 +0000</pubDate>
      <link>https://dev.to/surgbc/chainbrake-building-the-worlds-cheapest-agricultural-robot-15kk</link>
      <guid>https://dev.to/surgbc/chainbrake-building-the-worlds-cheapest-agricultural-robot-15kk</guid>
      <description>&lt;p&gt;Chainbrake is our attempt at building the world's cheapest agricutural robot, Africa's version of farmbot cheap enough to be afforded in Africa.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This repo has been archived. We have stopped work on this project, as a result of which we will neither edit nor write any further articles on the work of developing chainbrake. Please have a look at the &lt;a href="https://dev.to/surgbc/brian-mechanism-building-the-worlds-cheapest-large-scale-agricultural-robot-49jb"&gt;Brian Mechanism Project&lt;/a&gt; which is the project that has taken over chainbrake in building the world's cheapest robot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The following is a &lt;a href="https://www.cseco.co.ke"&gt;cseco&lt;/a&gt; project which we'd like to run parallel with &lt;a href=""&gt;Kataa Queue&lt;/a&gt;. It is intended to run for 4 - 6 weeks. And with the limited resources that we have in our R&amp;amp;D department at CSECO, where our main goal is developing solutions that are cheap enough to be afforded in Africa, we are looking for an affordable way we can run the rest of the project.&lt;/p&gt;

&lt;p&gt;Over the course of 4 years at CSECO, we have worked on a number of projects, some which we worked on as consultants, but some have been our own projects which we have always been happy to opensource. But we have been learning a lot along the way, especially on (1) software architecture and (2) project management. What we are still in the process of learning is how to make enough money from our projects which is commensurate to the effort we put into them. For instance, our work which detected &lt;em&gt;a firmware bug on a series of Huawei routers(ONT) which enables internet access without an active subscription&lt;/em&gt;(we will document this soon. It is currently available at a &lt;a href="https://github.com/csecureline/safRouters"&gt;private repo&lt;/a&gt;) or &lt;a href="https://dev.to/surgbc/using-github-and-mermaidjs-to-document-software-architecture-using-c4-model-57fn"&gt;the buggy Mombasa Water portal which enables access to all customer balance data&lt;/a&gt;, or &lt;a href="https://github.com/thingsboardMod/DashboardFromCustomMenu"&gt;the customization of thingsboard&lt;/a&gt; which is also under a private repo, etc.&lt;/p&gt;

&lt;p&gt;We have however, been able to successfully &lt;a href="https://dev.to/surgbc/using-github-and-mermaidjs-to-document-software-architecture-using-c4-model-57fn"&gt;develop a means of documenting software architecture&lt;/a&gt;. And this series of articles is an attempt to develop a simple means of project management, for projects that require more than the writing of code; right from ideation to system design, to the design of both hardware and software components of the system, to software development and the fabrication of the hardware components.&lt;/p&gt;

&lt;p&gt;We have proposed to have a system of writing publicly whatever parts of the project we would like to opensource and have have the proprietery sections documented in private repos.&lt;/p&gt;

&lt;p&gt;The present project involves building the world's cheapest Agricultural robot. It has been long in the making, but now all things are set and a prototype of it should be up and testing in the next 6 weeks. The inspiration for this project came from &lt;a href="https://farm.bot/"&gt;FarmBot&lt;/a&gt;. But as shall be been from the concept document up ahead, farmbot is too expensive for us Africans. See the buyer distribution map below to understand what we mean. There are but two Africans living in Africa how have been able to buy Farmbot, which, as shall also be seen, can be rightly classified as a very dear educational toy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_8i6lYVy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lnsipvwqr0xt9wskz914.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_8i6lYVy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lnsipvwqr0xt9wskz914.jpg" alt="Image description" width="880" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the course of the years, we have worked on &lt;a href="https://www.youtube.com/watch?v=8nenq15aCas&amp;amp;t=606s&amp;amp;ab_channel=CSECO"&gt;a simulator for farmbot&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=2C6HqIM0224&amp;amp;t=27s&amp;amp;ab_channel=CSECO"&gt;a number of mechanisms&lt;/a&gt; which we proposed for building affordability into the proposed robot. But now we have finally settled for a &lt;a href="https://chainbrake.github.io/"&gt;chainbrake mechanism&lt;/a&gt; as the means of actuating the robot. It shall also be seen why this choice was made. Although the chainbrake mechanism is an opensource design, we are in the process of working on an IP for a chainbrake actuator. All this is part of the current project. We shall now go on ahead to look at the &lt;a href="https://dev.to/surgbc/chainbrake-building-the-worlds-cheapest-agricultural-robot-timeline-3jdd"&gt;project timeline&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>robotics</category>
      <category>go</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Using Github and MermaidJs to Document Software Architecture Using C4 Model</title>
      <dc:creator>Brian Onang'o</dc:creator>
      <pubDate>Tue, 15 Mar 2022 12:30:24 +0000</pubDate>
      <link>https://dev.to/surgbc/using-github-and-mermaidjs-to-document-software-architecture-using-c4-model-57fn</link>
      <guid>https://dev.to/surgbc/using-github-and-mermaidjs-to-document-software-architecture-using-c4-model-57fn</guid>
      <description>&lt;p&gt;UML is a popular standard for developing software architecture. But it has an alternative in thee C4 model. The C4 model is an "abstraction-first" approach to diagramming software architecture, based upon abstractions that reflect how software architects and developers think about and build software. For more information about the C4 model, please visit &lt;a href="https://c4model.com" rel="noopener noreferrer"&gt;its website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The C4 model consists of hierarchical diagrams in 4 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The System &lt;strong&gt;Context&lt;/strong&gt; Diagram&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt; Diagram showing the independently deployable parts of the sytem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Components&lt;/strong&gt; of the containers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;More information is made available as we go down the hierarchy, more like zooming into a map. To be able to visualize C4 models, we have to have a system that is able to take us from one item up in the hierarchy to its children down the hierarchy. There are not that many tools that are able to work with C4 models yet, these being limited to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://gaphor.org/" rel="noopener noreferrer"&gt;Gaphor&lt;/a&gt;. This is a free desktop application&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/plantuml-stdlib/C4-PlantUML" rel="noopener noreferrer"&gt;C4-plantuml&lt;/a&gt; which provides a VS-Code extension&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/goadesign/model" rel="noopener noreferrer"&gt;goadesign&lt;/a&gt; for creating software architecture models and diagrams in Go&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://structurizr.com/" rel="noopener noreferrer"&gt;structurizr&lt;/a&gt; which is proprietary software from Simon Brown, the developer of the C4 model.&lt;/li&gt;
&lt;li&gt;MermaidJs, which is free and can be used in github markdown files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are going to show how to build simple models using mermaid JS, with an example available at &lt;a href="https://github.com/csymapp/mermaid-c4-model" rel="noopener noreferrer"&gt;mermaid-c4-model&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using mermaid in a github md file
&lt;/h2&gt;

&lt;p&gt;Include a code section with mermaid as the language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```mermaid
% mermaid code goes here
```
## Choosing Diagram type
Mermaid supports a number of diagram types. We will use `flowchart TB` for our C4 model diagrams.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TB
% the rest of mermaid code goes here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Subgraphs
&lt;/h2&gt;

&lt;p&gt;MermaidJs was not intended for building diagrams with a lot of information as in the detailed C4 model diagrams. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem7g9iqegfyb1wix6lj6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem7g9iqegfyb1wix6lj6.png" alt="User Diagram" width="220" height="168"&gt;&lt;/a&gt;&lt;br&gt;
Consider the user diagram for example. We cannot possibly include all that info in a single mermaid object. So we choose &lt;code&gt;subgraphs&lt;/code&gt; as our basic units. We will still not be able to get the icons into the subgraphs. But they are not absolutely necessary.&lt;/p&gt;

&lt;p&gt;To build the user diagram above in mermaid, we use a subgraph and 2 other objects (A1 and B1) inside the subgraph. The subgraph and A1 have the same color applied to them. B1 can retain have the default object color.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% color definition
classDef gray fill:#62524F, color:#fff
subgraph publicUser[ ]
    A1[[Public User&amp;lt;br/&amp;gt; Via REST API]]
    B1[Backend Services/&amp;lt;br/&amp;gt;frontend services]
end
% Apply the color to subgraph and A1
class publicUser,A1 gray
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8g1o8m1n57mnj3xdeewy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8g1o8m1n57mnj3xdeewy.png" alt="userDiagramMermaid" width="158" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each subgraph representing a single object has an &lt;code&gt;Ai&lt;/code&gt; and a &lt;code&gt;Bi&lt;/code&gt; object. Where &lt;code&gt;i&lt;/code&gt; is the number of the subgraph. When applying a color or any other style, we apply it to both the &lt;code&gt;subgraph&lt;/code&gt; and the &lt;code&gt;Ai&lt;/code&gt; object.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using Legends
&lt;/h2&gt;

&lt;p&gt;A different mermaid object is used to create the legend. A subgraph holds different objects having different colors applied representing the different types of elements in the model, with a description in the object text. For example, the legend below is created using the following code:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfaogxlp75o7man6wuwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfaogxlp75o7man6wuwp.png" alt="Legend Example" width="189" height="360"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TB
classDef borderless stroke-width:0px
classDef darkBlue fill:#00008B, color:#fff
classDef brightBlue fill:#6082B6, color:#fff
classDef gray fill:#62524F, color:#fff
classDef gray2 fill:#4F625B, color:#fff

subgraph Legend[Legend]
    Legend1[person]
    Legend2[system]
    Legend3[external person]
    Legend4[external system]
end
class Legend1 darkBlue
class Legend2 brightBlue
class Legend3 gray
class Legend4 gray2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Opening Container Diagrams from Context Diagram and going further down the hierarchy
&lt;/h2&gt;

&lt;p&gt;To open a container diagram, we implement a &lt;code&gt;click&lt;/code&gt; event handler on the object representing the system having the container diagram. In the following example, the Books system has a container diagram representing more detailed info about the system.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8l58wzk6u52szt359fy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8l58wzk6u52szt359fy.png" alt="Context Diagram" width="800" height="589"&gt;&lt;/a&gt;&lt;br&gt;
To open the container diagram, we implement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;subgraph booksSystem[ ]
    A3[[Books System]]
    B3[Allows interacting with book records]
end
class booksSystem,A3 brightBlue

click A3 "/csymapp/mermaid-c4-model/blob/master/containerDiagram.md" "booksSystem"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The click event does not work with subgraphs. That is why we use &lt;code&gt;A3&lt;/code&gt; instead of &lt;code&gt;booksSystem&lt;/code&gt;.&lt;br&gt;
The url supplied has to be either absolute pointing to the container diagram, or relative to '&lt;a href="https://github.com" rel="noopener noreferrer"&gt;https://github.com&lt;/a&gt;'. It seems that we cannot supply a path relative to our repo yet. This means that if this repo is forked, then the path has to be editted to reflect its new location.&lt;/p&gt;

&lt;p&gt;The same is done for opening a &lt;code&gt;component diagram&lt;/code&gt; from a &lt;code&gt;container diagram&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since the click event is on the &lt;code&gt;A&lt;/code&gt; node inside the subgraph, we have to be sure to click on it, rather than on the subgraph itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  A little issue
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;For large models, github seems not to have a way of scaling it up so that the text and other objects are visible. Zooming in the page does not zoom in the iframe rendering the svg.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All in all, its a wonderful way to start documenting simple software architectures.&lt;/p&gt;

&lt;p&gt;The full example is available in &lt;a href="https://github.com/csymapp/mermaid-c4-model" rel="noopener noreferrer"&gt;this github repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The C4 model is pretty easy to use, so start designing your software in a way that you can share your design with others.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>c4model</category>
      <category>mermaidjs</category>
    </item>
    <item>
      <title>Using Bash to Scrape Data from Mombasa Water Portal</title>
      <dc:creator>Brian Onang'o</dc:creator>
      <pubDate>Tue, 15 Mar 2022 09:59:24 +0000</pubDate>
      <link>https://dev.to/surgbc/using-bash-to-scrape-data-from-mombasa-water-portal-2kno</link>
      <guid>https://dev.to/surgbc/using-bash-to-scrape-data-from-mombasa-water-portal-2kno</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is intended to show some of the poor practices of implementing buggy IT systems, which are available to the public, with proof of concept tools to exploit the buggy systems, with a view to having the bugs fixed and raising the standard of Software Engineering practice in Kenya.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of the many Water and Sanitation companies in Kenya, &lt;a href="https://portal.mombasawater.co.ke/index.php"&gt;Mombasa Water&lt;/a&gt; and Nairobi Water seem to be among the few, if not the only ones, that have digitized their records and provided an online portal for their customers to check their records. Mombasa Water, however, in classical style, has implemented its system in a such a buggy way that it exposes all the accounts and their balances to the public. More than a year later, the bug has remained unfixed.&lt;/p&gt;

&lt;p&gt;The portal itself does not use any authentication. This seems to be common practice with water, and utility providers seeing as &lt;a href="https://selfservice.kplc.co.ke/"&gt;KPLC self-service portal&lt;/a&gt; is designed in almost the same way. KPLC, however, implements some authentication and a token is required to access the &lt;a href="https://selfservice.kplc.co.ke/api/publicData/2.0.1/?accountReference=xxxx"&gt;API end point&lt;/a&gt; that returns data for a specific meter. But this token is not generated by the user from his credentials. This then provides security only against bots.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Cu37S_4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7gkn0egxhat3f41crlz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cu37S_4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7gkn0egxhat3f41crlz.png" alt="KPLC self service portal" width="880" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The KPLC portal allows a user to query data for a specific Meter Number or Account Number. It is the same with the Mombasa Water Portal. And since it is very difficult to guess an account number or a meter number, these systems provide some rudimentary security against exposing all user data. KPLC has another trick. While the call to the API returns the name of the account holder as well as the other info, the name is filtered out and not shown in the table of the records displayed in the UI. This shows that there could be some privacy concern with them about having all this info available to the public. Whether there are already data laws that forbid such a practice, we know not. But we know that this practice is surely a violation of the privacy of its users.&lt;/p&gt;

&lt;p&gt;But the designers and implementers of the Mombasa Water Portal are even worse. Their system does not even seem to have an API. To query it, you need to send a POST request to the page &lt;code&gt;https://portal.mombasawater.co.ke/index.php&lt;/code&gt; with the &lt;code&gt;search=ACCOUNT_NUMBER&lt;/code&gt;. This can be done in bash using &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s2"&gt;"search=ACCOUNT_NUMBER"&lt;/span&gt; https://portal.mombasawater.co.ke/index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lacks the basic security that is provided by the KPLC system against brute-force account guessing bots.&lt;/p&gt;

&lt;p&gt;Supplying a space character for the account number returns a list having the customer name and account number of all the accounts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s2"&gt;"search= "&lt;/span&gt; https://portal.mombasawater.co.ke/index.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get account number and customer name we use grep and sed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s2"&gt;"search= "&lt;/span&gt; https://portal.mombasawater.co.ke/index.php | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"Account Number.*"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/Customer Name:&amp;lt;div&amp;gt;/:/'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/Account Number:&amp;lt;div&amp;gt;//'&lt;/span&gt; |grep &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"[0-9]*:.*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To sort the data and save to a text file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s2"&gt;"search= "&lt;/span&gt; https://portal.mombasawater.co.ke/index.php | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"Account Number.*"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/Customer Name:&amp;lt;div&amp;gt;/:/'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/Account Number:&amp;lt;div&amp;gt;//'&lt;/span&gt; |grep &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"[0-9]*:.*"&lt;/span&gt; |sort &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mw.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fetching Account Balances
&lt;/h2&gt;

&lt;p&gt;Account balances can be fetched by entering the account number into the &lt;code&gt;Account Number Field&lt;/code&gt; of the &lt;a href="https://portal.mombasawater.co.ke/index.php"&gt;form at the portal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This task can also be automated using bash. &lt;br&gt;
For a single account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s2"&gt;"search=ACCOUNT_NUMBER"&lt;/span&gt; https://portal.mombasawater.co.ke/index.php|grep &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"Customer Name:.*&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;Account Number:.*&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;Balance:.*"&lt;/span&gt;  | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;[^&amp;gt;]*&amp;gt;//g'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/\(Balance[^ ]*\) .*/\1/'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'\r\n'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/Customer Name:\(.*\)Account Number:\([0-9]*\)Balance:\(.*\)/\2:\3:\1/'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For all accounts. Save to txt file with name in the format &lt;code&gt;YYYY-MM-DDhh:hh:ss.balances&lt;/code&gt;&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;cat &lt;/span&gt;mw.txt | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/:.*//g'&lt;/span&gt; | parallel &lt;span class="nt"&gt;-j200&lt;/span&gt; &lt;span class="s2"&gt;"curl -sS --data &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;search={}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; https://portal.mombasawater.co.ke/index.php | grep -o &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Customer Name:.*&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;Account Number:.*&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;Balance:.*&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; | sed -e 's/&amp;lt;[^&amp;gt;]*&amp;gt;//g' | sed -e 's/&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;Balance[^ ]*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt; .*/&lt;/span&gt;&lt;span class="se"&gt;\1&lt;/span&gt;&lt;span class="s2"&gt;/' |  tr -d '&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;'|sed -e 's/&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;Customer Name&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n\r\1&lt;/span&gt;&lt;span class="s2"&gt;/g' | sed -e 's/Customer Name:&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;Account Number:&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;Balance:&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\2&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\3&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\t\1&lt;/span&gt;&lt;span class="s2"&gt;/g' &amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="se"&gt;\"&lt;/span&gt;%F%T&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.balances&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; echo {#}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one liner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s2"&gt;"search= "&lt;/span&gt; https://portal.mombasawater.co.ke/index.php | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"Account Number.*"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/Customer Name:&amp;lt;div&amp;gt;/:/'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/Account Number:&amp;lt;div&amp;gt;//'&lt;/span&gt; |grep &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"[0-9]*:.*"&lt;/span&gt; |sort | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/:.*//g'&lt;/span&gt; | parallel &lt;span class="nt"&gt;-j200&lt;/span&gt; &lt;span class="s2"&gt;"curl -sS --data &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;search={}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; https://portal.mombasawater.co.ke/index.php | grep -o &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Customer Name:.*&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;Account Number:.*&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;Balance:.*&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; | sed -e 's/&amp;lt;[^&amp;gt;]*&amp;gt;//g' | sed -e 's/&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;Balance[^ ]*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt; .*/&lt;/span&gt;&lt;span class="se"&gt;\1&lt;/span&gt;&lt;span class="s2"&gt;/' |  tr -d '&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s2"&gt;'|sed -e 's/&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;Customer Name&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n\r\1&lt;/span&gt;&lt;span class="s2"&gt;/g' | sed -e 's/Customer Name:&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;Account Number:&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;Balance:&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\2&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\3&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\t\1&lt;/span&gt;&lt;span class="s2"&gt;/g' &amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="se"&gt;\"&lt;/span&gt;%F%T&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.balances&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; echo {#}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that single line a malicious actor is able to get the balance records, with the names for all accounts, of Mombasa Water as frequently as he likes and use that data for whatever on earth it can be used for. Our solution to this challenge, as well as for helping other WASH players to get up to speed with technological advancements is the &lt;a href="https://github.com/csymapp/openWASH"&gt;openWASH&lt;/a&gt;, the open source WASH Management Information System. It may be several months or years away, but it's well in the pipeline.&lt;/p&gt;

</description>
      <category>mombasawater</category>
      <category>datamining</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>Creating a searchable knowledge-base from several PDF files</title>
      <dc:creator>Brian Onang'o</dc:creator>
      <pubDate>Tue, 01 Mar 2022 12:11:46 +0000</pubDate>
      <link>https://dev.to/surgbc/creating-a-searchable-knowledge-base-from-several-pdf-files-4deh</link>
      <guid>https://dev.to/surgbc/creating-a-searchable-knowledge-base-from-several-pdf-files-4deh</guid>
      <description>&lt;h2&gt;
  
  
  Part 1 - Exploring the Power of Bash
&lt;/h2&gt;

&lt;p&gt;In the current project we are going to work with several isolated PDF files, converting them into a searchable knowledge base. We are going to see how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Download&lt;/strong&gt; a file from a website using a script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scrape&lt;/strong&gt; an html table for links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch download&lt;/strong&gt; several files in parallel without running out of memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine pdf files&lt;/strong&gt; using a script&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch rename files&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Create a website from pdf files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before we begin, let us give a little background for the project. We have quarterly Bible study guides that have faithfully been produced every year since 1886. All of these have been digitized and &lt;a href="https://www.adventistarchives.org/sabbathschoollessons" rel="noopener noreferrer"&gt;are available for all years since 1888&lt;/a&gt; (also available &lt;a href="https://documents.adventistarchives.org/SSQ/Forms/AllItems.aspx" rel="noopener noreferrer"&gt;here&lt;/a&gt;). Like in all areas, the faithful student is he that compares the current studies with what has been done in the past. This comparison will help in understanding the subject under consideration more deeply and in seeing if there are any errors that have been introduced in the new, or if there were errors in the old. And Christ said that "every scribe instructed concerning the kingdom of heaven is like a householder who &lt;strong&gt;&lt;em&gt;brings out of his treasure things new and old&lt;/em&gt;&lt;/strong&gt;."&lt;/p&gt;

&lt;p&gt;To be able to make use of the old guides, the student currently has to go to the index of titles and check for the guides relevant to his subject of study, download all the pdf files individually, the reading each of them. But it would be more desirable to have a searchable knowledge-base having all these guides which the student can search whatever he needs at once, without having to manage 500+ individual files. It is such a system that we will be building.&lt;/p&gt;

&lt;p&gt;In the first step we are going to:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Download a pdf file from a website using a script
&lt;/h2&gt;

&lt;p&gt;The first lesson available is found at the following link: &lt;code&gt;http://documents.adventistarchives.org/SSQ/SS18880101-01.pdf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Downloading this single file is pretty straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget http://documents.adventistarchives.org/SSQ/SS18880101-01.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But since there are over 500 files and we cannot possibly copy and paste the link one by one from the site and download them, we are going to:&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Scape the page for links to pdf files
&lt;/h2&gt;

&lt;p&gt;All the pdf files we need are available in the directory being served at &lt;code&gt;http://documents.adventistarchives.org/SSQ/&lt;/code&gt;. But trying to access that directory does not give a listing of the files in it, but rather redirects to a different page. We would use &lt;code&gt;recursive wget&lt;/code&gt; to download all those files if accessing the directory gave a listing of the files it contains. But since this is not available to us, we have to use some other method.&lt;/p&gt;

&lt;p&gt;Since we already know that all the files we are looking for have &lt;code&gt;http://documents.adventistarchives.org/SSQ/&lt;/code&gt; in their url. That is going to form the basis for our pattern. The final command that we have to extract both the url of the pdf file and the lesson title for that pdf 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="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; files.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://www.adventistarchives.org/sabbathschoollessons | &lt;span class="nb"&gt;grep&lt;/span&gt;  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'http://documents.adventistarchives.org/SSQ/[^.]*.pdf\"[^\&amp;gt;]*[^\&amp;lt;]*'&lt;/span&gt; | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;line &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/\"[^\&amp;gt;]*./ /'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/  \+/ /g'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; files.txt&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;grep -o&lt;/code&gt; will print only the matches found.&lt;/p&gt;

&lt;p&gt;The result is saved in &lt;code&gt;files.txt&lt;/code&gt;. Each line has the pdf url and the lesson title for that pdf.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkbph31vfs8yn4h508h3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkbph31vfs8yn4h508h3.png" alt="files.txt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To see the number of files that we will be dealing with we can do &lt;code&gt;wc -l files.txt&lt;/code&gt;. There are 516 files in total.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Downloading all 510 files
&lt;/h2&gt;

&lt;p&gt;The files are in reality a little fewer than 516 because the list contains duplicates since it is designed for every quarter whereas some pdf files have two quarters. To remove the duplicated urls, we use sort:&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;sort&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; files.txt files.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To download the files, we need to get the url for each file from &lt;code&gt;files.txt&lt;/code&gt;. We can do this by&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;cat &lt;/span&gt;files.txt |while &lt;span class="nb"&gt;read &lt;/span&gt;line &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; 1 &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; |xargs wget&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this downloads one file at a time and is as a result very slow and inefficient.&lt;/p&gt;

&lt;p&gt;To download the files in parallel, we use wget with the '-b' option so that it can fork itself. We sort the urls file to remove duplicated urls since files.txt has duplicated urls and not duplicated lines because of different lesson titles for the duplicated urls.&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;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="se"&gt;\ &lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt;  files.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; urls &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; urls urls &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;urls |while &lt;span class="nb"&gt;read &lt;/span&gt;line &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; 1 &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; |xargs wget &lt;span class="nt"&gt;-b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are probably very lucky to download all the 510 files in 5 seconds without running out of 1GB of memory. It would be interesting to know how this would perform in node.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Combine 510 pdfs into 1
&lt;/h2&gt;

&lt;p&gt;The first obvious step in making our knowledge-base is probably combining all the pdfs into one. This will result in a single big pdf (over 100mbs in size), but much more useful in study if it can be opened than 510 separate pdfs. For this we are going to use &lt;code&gt;ghostscript&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gs &lt;span class="nt"&gt;-dBATCH&lt;/span&gt; &lt;span class="nt"&gt;-dNOPAUSE&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-sDEVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pdfwrite &lt;span class="nt"&gt;-sOutputFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;allLessons.pdf &lt;span class="k"&gt;*&lt;/span&gt;.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ghostscript quickly runs us out of memory. A better alternative for this task could be &lt;code&gt;pdfunite&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pdfunite &lt;span class="k"&gt;*&lt;/span&gt;.pdf allLessons.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pdfunite&lt;/code&gt; gets us a bigger file, but it is also runs us out of memory. Using NitroPro on windows in a system having 8GB of RAM gives us a file of 708.4Mb. It would be interesting to see if this would also be possible in a single core 1GB RAM system like the linux one we are trying to force to work for us. &lt;/p&gt;

&lt;p&gt;Let's try pdfunite on 10 files at a time. We will use &lt;code&gt;GNU parallel&lt;/code&gt; and let it do what it can to manage the memory for us. This process takes about &lt;strong&gt;&lt;em&gt;20 minutes&lt;/em&gt;&lt;/strong&gt; and outputs files 1.pdf ... 51.pdf which we need to further combine.&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-lha&lt;/span&gt; ./ |grep SS.&lt;span class="k"&gt;*&lt;/span&gt;pdf | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'[^ ]*$'&lt;/span&gt; |parallel &lt;span class="nt"&gt;-N10&lt;/span&gt; pdfunite &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="c"&gt;#}.pdf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Creating a site where pdfs can be downloaded.
&lt;/h2&gt;

&lt;p&gt;We are going to do this using github pages. To do this we are first going to create a CNAME entry in our DNS server to point to github pages.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CNAME&lt;/th&gt;
&lt;th&gt;ttl&lt;/th&gt;
&lt;th&gt;points to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;sslpdfs&lt;/td&gt;
&lt;td&gt;900&lt;/td&gt;
&lt;td&gt;gospelsounders.github.io.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Then we are going to add a CNAME file with the contents &lt;code&gt;sslpdfs.gospelsounders.org&lt;/code&gt;, commit and push repo to github, and configure the github pages settings in the github repo.&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="nv"&gt;GIT_SSH_COMMAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ssh -i /tmp/gitKey -o IdentitiesOnly=yes'&lt;/span&gt; git push origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we should create the index of the files that we have and put them in README.md. The following bash commands do this for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://www.adventistarchives.org/sabbathschoollessons |grep &lt;span class="nt"&gt;-o&lt;/span&gt; ^[&lt;span class="se"&gt;\&amp;lt;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;td.&lt;span class="k"&gt;*&lt;/span&gt; |sed &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;td[^\&amp;gt;]*&amp;gt;//g'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;sup&amp;gt;.*&amp;lt;\/sup&amp;gt;//g'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;\/td&amp;gt;//g'&lt;/span&gt; |sed &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/\&amp;lt;a.*href="[^h][^t][^t][^p][^:][^&amp;gt;]*&amp;gt;.*&amp;lt;\/a&amp;gt;&amp;lt;//'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;a[^&amp;gt;]*&amp;gt;&amp;lt;\/a&amp;gt;//g'&lt;/span&gt; |sed &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;[^a][^&amp;gt;]*&amp;gt;//g'&lt;/span&gt; |grep &lt;span class="nt"&gt;-A&lt;/span&gt; 2 &lt;span class="s1"&gt;'^[0-9]\{4\}'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"^--$"&lt;/span&gt; |parallel &lt;span class="nt"&gt;-N3&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/\(&amp;lt;a[^&amp;lt;]*\)\(&amp;lt;.*\)/\1/g'&lt;/span&gt;| &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;a.* href="\([^"]*\)"[^&amp;gt;]*&amp;gt;\(.*\)/[\2](\1)/'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/  */ /g'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/http:\/\/documents.adventistarchives.org\/SSQ\///'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/ \]/\]/g'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It produces a list in the following format:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzx563v6du2bw5zvohhi4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzx563v6du2bw5zvohhi4.png" alt="IndexofTitles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But we would desire to have all the quarters of a year in a single row in a table having the following header:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Quarter 1&lt;/th&gt;
&lt;th&gt;Quarter 2&lt;/th&gt;
&lt;th&gt;Quarter 3&lt;/th&gt;
&lt;th&gt;Quarter 4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With the header already in the markdown file (README.md), the following commands create the table for us and add it to the markdown file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://www.adventistarchives.org/sabbathschoollessons |grep &lt;span class="nt"&gt;-o&lt;/span&gt; ^[&lt;span class="se"&gt;\&amp;lt;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;td.&lt;span class="k"&gt;*&lt;/span&gt; |sed &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;td[^\&amp;gt;]*&amp;gt;//g'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;sup&amp;gt;.*&amp;lt;\/sup&amp;gt;//g'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;\/td&amp;gt;//g'&lt;/span&gt; |sed &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/\&amp;lt;a.*href="[^h][^t][^t][^p][^:][^&amp;gt;]*&amp;gt;.*&amp;lt;\/a&amp;gt;&amp;lt;//'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;a[^&amp;gt;]*&amp;gt;&amp;lt;\/a&amp;gt;//g'&lt;/span&gt; |sed &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;[^a][^&amp;gt;]*&amp;gt;//g'&lt;/span&gt; |grep &lt;span class="nt"&gt;-A&lt;/span&gt; 2 &lt;span class="s1"&gt;'^[0-9]\{4\}'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"^--$"&lt;/span&gt; |parallel &lt;span class="nt"&gt;-N3&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/\(&amp;lt;a[^&amp;lt;]*\)\(&amp;lt;.*\)/\1/g'&lt;/span&gt;| &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;a.* href="\([^"]*\)"[^&amp;gt;]*&amp;gt;\(.*\)/[\2](\1)/'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/  */ /g'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/http:\/\/documents.adventistarchives.org\/SSQ\///'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/ \]/\]/g'&lt;/span&gt; | parallel &lt;span class="nt"&gt;-N4&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/ [0-9]\{4\} [1-4][a-z]\{2\} / \|/g'&lt;/span&gt; |sed &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/ 1st /\| /'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; README.md 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Continue combining the 51 files
&lt;/h2&gt;

&lt;p&gt;We first have to add a leading zero to the first 9 files, then run &lt;code&gt;pdfunite&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rename.ul &lt;span class="s2"&gt;""&lt;/span&gt; 0 ?.pdf

&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lha&lt;/span&gt; ./ |grep &lt;span class="s2"&gt;" [0-9][0-9]&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;pdf"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'[^ ]*$'&lt;/span&gt; |parallel &lt;span class="nt"&gt;-N10&lt;/span&gt; pdfunite &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="c"&gt;#}-2.pdf&lt;/span&gt;

&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lha&lt;/span&gt; ./ |grep &lt;span class="s2"&gt;" [0-9]-2&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;pdf"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'[^ ]*$'&lt;/span&gt; |parallel &lt;span class="nt"&gt;-N6&lt;/span&gt; pdfunite &lt;span class="o"&gt;{}&lt;/span&gt; allLessons.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last process still breaks because of limited memory. So we will upload the file that we created using NitroPro to our server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scp All&lt;span class="se"&gt;\ &lt;/span&gt;Lessons.pdf user@server:/tmp/pdfs/allLessons.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;allLessons.pdf&lt;/code&gt; is greater than 100MBs (708.4MB) and we can't push to github. We need to find a way of reducing its size. So let's try to remove the images from the pdfs and see the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gs &lt;span class="nt"&gt;-sDEVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pdfwrite &lt;span class="nt"&gt;-dFILTERVECTOR&lt;/span&gt; &lt;span class="nt"&gt;-dFILTERIMAGE&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; allLessonsSmall.pdf &lt;span class="s2"&gt;"allLessons.pdf"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are almost done as this gives us a file that is 68.5MBs. But the &lt;del&gt;text is white on a white background&lt;/del&gt;the text is transparent.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;Evince&lt;/code&gt;, the default pdf viewer for Ubuntu, the transparent-text pdf can be read by selecting all the text using &lt;code&gt;CTRL+A&lt;/code&gt; which will make the text visible. But this method seems not to work on all pdf viewers including 'Foxit Reader' and Adobe pdf readers. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkogloobu1f8xu5pmig1r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkogloobu1f8xu5pmig1r.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
We will therefore convert the transparent-text pdf to html and change the color in the generated css file.&lt;/p&gt;

&lt;p&gt;For this exercise we have chosen to use a digital ocean trial account to launch a 4 Core 8GB RAM 160 GB SSD server. The following command is executed unbelievably fast (2m8.701s):&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;time &lt;/span&gt;pdf2htmlEX &lt;span class="nt"&gt;--split-pages&lt;/span&gt; 1 &lt;span class="nt"&gt;--process-nontext&lt;/span&gt; 0 &lt;span class="nt"&gt;--process-outline&lt;/span&gt; 0 &lt;span class="nt"&gt;--process-annotation&lt;/span&gt; 0 &lt;span class="nt"&gt;--process-form&lt;/span&gt; 0 &lt;span class="nt"&gt;--embed-css&lt;/span&gt; 0 &lt;span class="nt"&gt;--embed-font&lt;/span&gt; 0 &lt;span class="nt"&gt;--embed-image&lt;/span&gt; 0 &lt;span class="nt"&gt;--embed-javascript&lt;/span&gt; 0 &lt;span class="nt"&gt;--embed-outline&lt;/span&gt; 0 &lt;span class="nt"&gt;--dest-dir&lt;/span&gt; html allLessonsSmall.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is 26672 files of total size 223MB. You can find these by running &lt;code&gt;ls html |wc -l&lt;/code&gt; and &lt;code&gt;du -h html&lt;/code&gt;. All text is still set to be transparent as seen from the following css file:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl79ghnbi1lnc67loljcv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl79ghnbi1lnc67loljcv.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
This is changed to black as follows:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6r9hyiz3smbchv5vdqjw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6r9hyiz3smbchv5vdqjw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Converting all the pdfs to html
&lt;/h2&gt;

&lt;p&gt;We will now convert the pdfs to html files, which will allow us to be able to search their contents within github. This is also an easy task using our free trial 4 core server:&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-lha&lt;/span&gt; ./ |grep SS.&lt;span class="k"&gt;*&lt;/span&gt;pdf | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'[^ ]*$'&lt;/span&gt; |parallel &lt;span class="nt"&gt;-N10&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/ /\n/g'&lt;/span&gt; | parallel &lt;span class="nt"&gt;-N1&lt;/span&gt; pdf2htmlEX &lt;span class="nt"&gt;--split-pages&lt;/span&gt; 1 &lt;span class="nt"&gt;--dest-dir&lt;/span&gt; htmls &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  8. Adding to git, commiting and pushing to github
&lt;/h2&gt;

&lt;p&gt;For some reason, these command add all the files at once.&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;ls&lt;/span&gt; ./|head &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;18135&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;|tail &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;18135&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;|xargs git add&lt;span class="sb"&gt;```&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;% endraw %&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;{&lt;/span&gt;% raw %&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="sb"&gt;```&lt;/span&gt;bash
&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; ./|head &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;18135&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;|tail &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;18135&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;git add &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we move the htmls folder out of our folder, recreate it  copy back the files in batches, add the files to git and commit. We run this command 5 times, incrementing the multiplier (1 in this command).&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="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; ../htmls|head &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;18135&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;|tail &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="m"&gt;18135&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"../htmls/&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; htmls/ &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"added batch of files"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Editing the index to add links to html files
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'/SS.*pdf/s/(\([^)]*\))/(htmls\/\1.html) \\| [⇩](\1)/g'&lt;/span&gt; README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  10. Converting all the pdfs to text
&lt;/h2&gt;

&lt;p&gt;In docs folder,&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-lha&lt;/span&gt; ./ |grep SS.&lt;span class="k"&gt;*&lt;/span&gt;pdf | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'[^ ]*$'&lt;/span&gt; |parallel &lt;span class="nt"&gt;-N10&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/ /\n/g'&lt;/span&gt; | parallel &lt;span class="nt"&gt;-N1&lt;/span&gt; pdftotext &lt;span class="nt"&gt;-layout&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lha&lt;/span&gt; ./ |grep &lt;span class="s2"&gt;"[0-9].txt"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'[^ ]*$'&lt;/span&gt; |parallel &lt;span class="nt"&gt;-N10&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/ /\n/g'&lt;/span&gt; | parallel &lt;span class="nt"&gt;-N1&lt;/span&gt; &lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; texts/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  11. Remove transparency from htmls
&lt;/h2&gt;

&lt;p&gt;The htmls contain transparent text which we wish to convert to black. In &lt;code&gt;docs/htmls&lt;/code&gt; run:&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;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'/fc0{color:transparent;/s/transparent/black/'&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.html
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'/fc0{color:transparent;/s/transparent/black/'&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  12. Add text files to index
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'/SS.*pdf/s/(\([^(]*\).pdf)/(\1.pdf) \\| [txt](texts\/\1.txt)/g'&lt;/span&gt; README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>knowledgebase</category>
      <category>bash</category>
      <category>combinepdf</category>
      <category>websitefrompdf</category>
    </item>
  </channel>
</rss>
