<?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: Simon Richard</title>
    <description>The latest articles on DEV Community by Simon Richard (@jsimonrichard).</description>
    <link>https://dev.to/jsimonrichard</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%2F388832%2F787ef736-203c-4bf3-9324-2504296f8ef6.jpg</url>
      <title>DEV Community: Simon Richard</title>
      <link>https://dev.to/jsimonrichard</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jsimonrichard"/>
    <language>en</language>
    <item>
      <title>MongoDB Hackathon Submission - QrTracker</title>
      <dc:creator>Simon Richard</dc:creator>
      <pubDate>Thu, 13 Jan 2022 23:56:32 +0000</pubDate>
      <link>https://dev.to/jsimonrichard/mongodb-hackathon-submission-qrtracker-1lef</link>
      <guid>https://dev.to/jsimonrichard/mongodb-hackathon-submission-qrtracker-1lef</guid>
      <description>&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://qrtracker-yibtf.mongodbstitch.com/"&gt;QrTracker&lt;/a&gt; is a multi-purpose tracking alternative that gives small business owners (or anyone else, really) the ability to create, as well as consume, tracking information.&lt;/p&gt;

&lt;p&gt;It's similar to the software that companies like FedEx and UPS use to give their customers tracking information, but it's open source.&lt;/p&gt;

&lt;p&gt;QrTracker also allows for more freedom in how it's used; it supports, but does not require, geographical information.&lt;/p&gt;

&lt;p&gt;Sign up at &lt;a href="https://qrtracker-yibtf.mongodbstitch.com/"&gt;https://qrtracker-yibtf.mongodbstitch.com/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Action Star&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jsimonrichard"&gt;
        jsimonrichard
      &lt;/a&gt; / &lt;a href="https://github.com/jsimonrichard/QrTracker-atlas-hackathon"&gt;
        QrTracker-atlas-hackathon
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Submission for the Atlas Hackathon put on by MongoDB and dev.to
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XHe4lLDY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sbmo20u63jruprkget19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XHe4lLDY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sbmo20u63jruprkget19.png" alt="Landing page" width="880" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xixmBABQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dq5bs8wafw9pcgorkg2l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xixmBABQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dq5bs8wafw9pcgorkg2l.png" alt="Create tracker form" width="372" height="663"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UmyTLE-6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s358jeelj65gezmjvvyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UmyTLE-6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s358jeelj65gezmjvvyp.png" alt="Dashboard" width="880" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2smNsN8G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0ltlue5xnsphlyg2eo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2smNsN8G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0ltlue5xnsphlyg2eo1.png" alt="Update status form" width="880" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--at4p3bI4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8n1d7a9ahfsreffmm1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--at4p3bI4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8n1d7a9ahfsreffmm1v.png" alt="Email notification" width="759" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rQwgIwW5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a4xoh9rxu131mkfxd7pi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rQwgIwW5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a4xoh9rxu131mkfxd7pi.png" alt="Edit tracker form" width="880" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MongoDB Technologies Used
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Realm Functions&lt;/li&gt;
&lt;li&gt;Realm Triggers&lt;/li&gt;
&lt;li&gt;Atlas Search&lt;/li&gt;
&lt;li&gt;GraphQL Integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other Technologies Used
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Git / GitHub&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reactjs.org/"&gt;ReactJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blueprintjs.com/"&gt;BlueprintJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://courier.com/"&gt;Courier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mailersend.com/"&gt;mailersend&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>atlashackathon</category>
      <category>actionstar</category>
    </item>
    <item>
      <title>Creating a Custom Ubuntu Server Disk Image for the Raspberry Pi with CustomPiOS</title>
      <dc:creator>Simon Richard</dc:creator>
      <pubDate>Thu, 16 Dec 2021 21:59:17 +0000</pubDate>
      <link>https://dev.to/jsimonrichard/creating-a-custom-ubuntu-server-disk-image-for-the-raspberry-pi-with-custompios-8mh</link>
      <guid>https://dev.to/jsimonrichard/creating-a-custom-ubuntu-server-disk-image-for-the-raspberry-pi-with-custompios-8mh</guid>
      <description>&lt;p&gt;This article will walk through the creation of a custom disk image for the Raspberry Pi. Possible use cases include...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making a Raspberry Pi disk image with all of your favorite apps pre-installed&lt;/li&gt;
&lt;li&gt;Making a distributable file for a product that runs on the Raspberry Pi (something like &lt;a href="https://octoprint.org/"&gt;OctoPrint&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this is made possible by &lt;a href="https://github.com/guysoft/CustomPiOS"&gt;CustomPiOS&lt;/a&gt;, a tool that opens, modifies, and repackages pre-existing ARM images (usually a Raspbian / Raspberry Pi OS image downloaded from the official website).&lt;/p&gt;

&lt;p&gt;This particular article will focus on making a 64-bit Ubuntu Server spin-off for the Raspberry Pi that runs docker-compose on boot. The process for making a Raspberry Pi OS spin-off is similar, but I would like to focus on the Ubuntu Server because it poses a few unique challenges that are worth covering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;First, let's clone the CustomPiOS github repo and cd into the &lt;em&gt;src&lt;/em&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/guysoft/CustomPiOS
&lt;span class="nb"&gt;cd &lt;/span&gt;CustomPiOS/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll also want to install these dependancies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;qemu-user-static p7zip-full
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on your machine, you may need some other dependencies as well. A full list can be found on the &lt;a href="https://github.com/guysoft/CustomPiOS#requirements"&gt;CustomPiOS github page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, we need to run the &lt;em&gt;make_custom_pi_os&lt;/em&gt; script. This will create a folder for our custom distro's config files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./make_custom_pi_os custom_distro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're creating a spin-off of Raspberry Pi OS, you may also want to add the &lt;code&gt;-g&lt;/code&gt; flag. This will automatically download the latest version of Rasbian / Raspberry Pi OS.&lt;/p&gt;

&lt;p&gt;Next, let's change directory into the folder we just created&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;custom_distro/src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the directory we'll be working in from now on. It's structure should be as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── build_dist
├── config
├── custompios_path
├── image
│   └── README
├── modules
│   └── custom_server
│       ├── config
│       ├── end_chroot_script
│       ├── filesystem
│       │   ├── boot
│       │   │   └── README
│       │   ├── home
│       │   │   ├── pi
│       │   │   │   └── README
│       │   │   └── root
│       │   │       └── README
│       │   └── root
│       │       └── README
│       └── start_chroot_script
└── vagrant
    ├── run_vagrant_build.sh
    ├── setup.sh
    └── Vagrantfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll do my best to explain what these files allow us to do, but I won't be able to touch on everything in detail.&lt;/p&gt;

&lt;p&gt;Let's start with...&lt;/p&gt;

&lt;h3&gt;
  
  
  The Config File
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;config&lt;/em&gt; file contains distro-wide settings. For those creating an Ubuntu Server spin-off, it should look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DIST_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;CustomDisto
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DIST_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.1
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MODULES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"base(network,docker,custom_distro)"&lt;/span&gt;


&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BASE_DISTRO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ubuntu
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BASE_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arm64

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BASE_ADD_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes
export &lt;/span&gt;&lt;span class="nv"&gt;BASE_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pi
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BASE_USER_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;12345

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BASE_IMAGE_ENLARGEROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4000
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BASE_IMAGE_RESIZEROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some of these variables are self-explanatory, but some are not. The &lt;code&gt;MODULES&lt;/code&gt; variable defines how functionality will be added to the base image (we'll talk more about that in a moment). The &lt;code&gt;BASE_IMAGE_ENLARGEROOT&lt;/code&gt; and &lt;code&gt;BASE_IMAGE_RESIZEROOT&lt;/code&gt; variables determine how the size of the image is increased before and after files are copied onto it (these two variables are optional; only use them if you need to).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Image Folder
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;image&lt;/em&gt; folder is where the base image for our custom distro should go. In fact, if you're following along, go ahead and download the 64-bit Ubuntu Server disk image file. It can be found &lt;a href="https://ubuntu.com/download/raspberry-pi"&gt;here&lt;/a&gt;. Don't extract the image, though. Simply place the compressed file in the &lt;em&gt;image&lt;/em&gt; directory.&lt;/p&gt;

&lt;p&gt;CustomPiOS should be able to find most images on its own, but it has trouble with the 64-bit Ubuntu image. If it's having trouble, set the base image path in the config file like so.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BASE_ZIP_IMAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;image/my_base_image.img.xz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Modules Folder
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;modules&lt;/em&gt; folder contains "modules" that add functionality to the custom distro. By default, a module of the same name as your custom distro folder was created when you ran the &lt;em&gt;make_custom_pi_os&lt;/em&gt; script. Within this module is a &lt;em&gt;filesystem&lt;/em&gt; folder, a &lt;em&gt;start_chroot_script&lt;/em&gt;, an &lt;em&gt;end_chroot_script&lt;/em&gt;, and another &lt;em&gt;config&lt;/em&gt; file.&lt;/p&gt;

&lt;p&gt;Let's break each of these down.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Filesystem Folder
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;filesystem&lt;/em&gt; folder contains all of the custom files that you would like to be present on your custom distro. It contains three sub-folders, each of which will unpacked at a different mount point: the &lt;em&gt;root&lt;/em&gt; folder will unpacked at the root directory, or &lt;em&gt;/&lt;/em&gt;; the &lt;em&gt;home&lt;/em&gt; folder will be unpacked at &lt;em&gt;/home&lt;/em&gt;; and the &lt;em&gt;boot&lt;/em&gt; directory will be unpacked in the boot partition (which is usually mounted at &lt;em&gt;/boot&lt;/em&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  The Start Chroot Script
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;start_chroot_script&lt;/em&gt; runs in a chroot environment on the disk image. Use this to install software, change file permissions, and/or do anything else that would require the use of terminal.&lt;/p&gt;

&lt;p&gt;In this script, you should also have access to a few extra commands (courtesy of the auto-generated line &lt;code&gt;source /common.sh&lt;/code&gt;): the &lt;code&gt;unpack&lt;/code&gt; command and the &lt;code&gt;gitclone&lt;/code&gt; command. More information can be found &lt;a href="https://github.com/guysoft/CustomPiOS#useful-commands-from-commonsh"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  The End Chroot Script
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;end_chroot_script&lt;/em&gt; can be used to clean up after the &lt;em&gt;start_chroot_script&lt;/em&gt;. A lot of modules don't use this, however. Feel free to delete it if you'd like. &lt;/p&gt;

&lt;h4&gt;
  
  
  The Module Config File
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;config&lt;/em&gt; file within the module folder can used to set environment variables for your own use within the start and end chroot scripts. By default, only an example variable is generated.&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;CUSTOM_DISTRO_VAR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"This is a module variable"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the variable name starts with &lt;code&gt;CUSTOM_DISTRO&lt;/code&gt;. For a variable to be exported, it's name must begin with the module name. Also, note the slight change in syntax from the global config file. Instead of using the &lt;code&gt;export&lt;/code&gt; command, these config files use &lt;em&gt;.env&lt;/em&gt; style syntax.&lt;/p&gt;

&lt;p&gt;Although you could hard-code values into the start and end chroot scripts, I would strongly recommend using these module-level config files. The variables exported from these files are also accessible in (and can be overridden by) the main config file. This greatly improves modularity; after you're done creating your custom distro, you could even release your custom_distro module as an add-on to CustomPiOS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Including Modules in the Final Disk Image
&lt;/h3&gt;

&lt;p&gt;Now, let's revisit this line in the main config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MODULES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"base(network,docker,custom_distro)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;MODULES&lt;/code&gt; defines which modules to include and how those modules should depend on each other. In the example above, three modules are included: &lt;code&gt;base&lt;/code&gt;, &lt;code&gt;network&lt;/code&gt;, &lt;code&gt;docker&lt;/code&gt;, and &lt;code&gt;custom_distro&lt;/code&gt;. The &lt;code&gt;network&lt;/code&gt;, &lt;code&gt;docker&lt;/code&gt;, and &lt;code&gt;custom_distro&lt;/code&gt; modules depend on (or extend, we could say) the &lt;code&gt;base&lt;/code&gt; module. In fact, every module must depend on the &lt;code&gt;base&lt;/code&gt; module. However, it can get more complicated. Here's another example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MODULES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"base(network(octopi, picamera))"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;octopi&lt;/code&gt; and &lt;code&gt;picamera&lt;/code&gt; depend on &lt;code&gt;network&lt;/code&gt;, which depends on &lt;code&gt;base&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I would also like to point out that we have access to quite a few built-in modules, including...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;admin-toolkit&lt;/li&gt;
&lt;li&gt;auto-hotspot&lt;/li&gt;
&lt;li&gt;auto-mount-removable&lt;/li&gt;
&lt;li&gt;cockpit&lt;/li&gt;
&lt;li&gt;docker&lt;/li&gt;
&lt;li&gt;gui&lt;/li&gt;
&lt;li&gt;usbconsole&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are a few of my favorites. A full list with descriptions can be found &lt;a href="https://github.com/guysoft/CustomPiOS/wiki/Modules#list-of-standard-library-modules"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building our Custom Ubuntu Server
&lt;/h2&gt;

&lt;p&gt;In order to create our custom Ubuntu Server, we're just going to make a few changes to the &lt;code&gt;custom_distro&lt;/code&gt; module.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting a Static IP
&lt;/h3&gt;

&lt;p&gt;In order to set a static IP, we'll create &lt;em&gt;etc/netplan/00-installer-config.yaml&lt;/em&gt; within the &lt;em&gt;filesystem/root&lt;/em&gt; directory of our module. Within this file, we'll save the following,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Static ip configuration&lt;/span&gt;
&lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ethernets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;eth0&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;addresses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;10.0.0.2/24&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;gateway4&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;10.0.0.1&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;nameservers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;addresses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;4.2.2.2&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;8.8.8.8&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;10.0.0.2&lt;/code&gt; is our static ip.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring docker-compose
&lt;/h3&gt;

&lt;p&gt;To configure docker-compose, simply create a folder called &lt;em&gt;docker-compose&lt;/em&gt; within the &lt;em&gt;root&lt;/em&gt; directory, and then place your &lt;em&gt;docker-compose.yml&lt;/em&gt; file within that folder along with another configuration files you might need (like a &lt;em&gt;.env&lt;/em&gt; file).&lt;/p&gt;

&lt;h3&gt;
  
  
  First-time Boot Script
&lt;/h3&gt;

&lt;p&gt;It's often helpful to have docker-compose start on boot. A restart flag can be set in the &lt;em&gt;docker-compose.yml&lt;/em&gt; file, but docker-compose still won't start on the first boot-up. To do that, we'll write first-time boot script.&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;filesystem/root/etc&lt;/em&gt; directory, create a file named &lt;em&gt;rc.local&lt;/em&gt;. Then, within that file, save the following contents.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nb"&gt;echo 
echo&lt;/span&gt; &lt;span class="s2"&gt;"==== Starting Docker Compose ===="&lt;/span&gt;
&lt;span class="nb"&gt;echo

pushd&lt;/span&gt; /docker-compose
  docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;span class="nb"&gt;popd

echo
echo&lt;/span&gt; &lt;span class="s2"&gt;"==== Docker Compose has been started ===="&lt;/span&gt;
&lt;span class="nb"&gt;echo

rm&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_SOURCE&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="c"&gt;# Remove this line if you want the script to run on every boot-up&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we'll need to make this script executable. We can do that easily within the &lt;em&gt;start_chroot_script&lt;/em&gt; by adding the following line to the end of the script.&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;chmod&lt;/span&gt; +x /etc/rc.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building the Image
&lt;/h2&gt;

&lt;p&gt;After finishing the configuration of our custom distro, we finally get to build our distributable image. This can be done by running the following command (make sure you're in the &lt;em&gt;custom_distro/src&lt;/em&gt; directory).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; ./build_dist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the command finishes (it can take some time), the resulting distributable image can be found in the newly created &lt;em&gt;custom_distro/src/workspace&lt;/em&gt; directory. It'll have the same name as the base image.&lt;/p&gt;

&lt;p&gt;If you encounter any errors, be sure to review the configuration files. You may also want to try one of the different build methods listed on the &lt;a href="https://github.com/guysoft/CustomPiOS"&gt;CustomPiOS github page&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;CustomPiOS is a really powerful tool, and I'm actually surprised there aren't more tutorials for it out there. It's been really useful to me, and I think a lot of other people would appreciate knowing how to use it.&lt;/p&gt;

&lt;p&gt;To check out some of the other projects that use CustomPiOS, take a look at &lt;a href="https://github.com/guysoft/CustomPiOS#list-of-distributions-using-custompios"&gt;this list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks so much for taking the time to read this article. I know it's kind of a long one, but I hope it's helpful. If you have any questions or if you find any errors in this article, please let me know in the comments below.&lt;/p&gt;

&lt;p&gt;Have a good one,&lt;br&gt;
- Simon&lt;/p&gt;

&lt;p&gt;SDG&lt;/p&gt;

&lt;p&gt;.&lt;br&gt;
.&lt;br&gt;
.&lt;br&gt;
.&lt;br&gt;
.&lt;br&gt;
Photo by &lt;a href="https://unsplash.com/@harrisonbroadbent?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Harrison Broadbent&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/raspberry-pi?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>raspberrypi</category>
      <category>linux</category>
      <category>devops</category>
    </item>
    <item>
      <title>Iterating through trees using the yield statement</title>
      <dc:creator>Simon Richard</dc:creator>
      <pubDate>Sat, 12 Dec 2020 17:03:35 +0000</pubDate>
      <link>https://dev.to/jsimonrichard/iterating-through-trees-using-the-yield-statement-2fod</link>
      <guid>https://dev.to/jsimonrichard/iterating-through-trees-using-the-yield-statement-2fod</guid>
      <description>&lt;p&gt;Data is often organized using tree like structures; JSON, XML, and File Directories are good examples of this. In this post, I would like to talk about how the keyword &lt;code&gt;yield&lt;/code&gt; (in combination with recursion) can be used to iterate easily through complex&lt;sup&gt;1&lt;/sup&gt; tree like structures.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;sup&gt;1&lt;/sup&gt; By complex, I mean multi-typed and messy.&lt;/small&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The &lt;code&gt;yield&lt;/code&gt; Statement
&lt;/h2&gt;

&lt;p&gt;For those who are not familiar with &lt;code&gt;yield&lt;/code&gt; statements in python, here's a quick explanation.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;yield&lt;/code&gt; statement allows a function to return a value and then continue running. In practice, this means turning the function into an iterator. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="n"&gt;my_iter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;my_iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;my_iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;my_iten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also use a for loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;my_iter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;my_iter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Recursion
&lt;/h2&gt;

&lt;p&gt;Recursion occurs when a function is executed inside of itself. This idea is especially helpful in relation to self similar structures, like trees. However, that function needs an exit point in order to actually be useful. Otherwise, it would run forever and return nothing. Let's look at some examples.&lt;/p&gt;

&lt;p&gt;This function will run forever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function will not run forever. Notice that it has an exit point, which is used when &lt;code&gt;x &amp;gt;= 5&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function prints all of the items of a nested array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_nested_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;print_nested_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one's a little more complicated; let's talk about it.&lt;/p&gt;

&lt;p&gt;The first value that's passed through this function is probably going to be an array (since we called the function &lt;code&gt;print_nested_array&lt;/code&gt;). In that case, the function will loop through that array and pass each of its items back into the function.&lt;/p&gt;

&lt;p&gt;For each item that is not an array, the function will print its string representation to the console. That's our exit point.&lt;/p&gt;

&lt;p&gt;If one of those items is also an array, it will go through the same process the initial array went through. Each of its items will be passed back into the function.&lt;/p&gt;

&lt;p&gt;Let's test it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;print_nested_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&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;1
2
3
4
5
6
7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Using Recursion and &lt;code&gt;yield&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;yield&lt;/code&gt; statement allows us to pass each of the items in our nested array back to the first instance of our function (the one that was not called using recursion), making it easier for us to access those values later on.&lt;/p&gt;

&lt;p&gt;To implement this, we'll only need to do few things to the previous function we used (shown below for convenience).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_nested_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;print_nested_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we'll replace the print statement with a &lt;code&gt;yield&lt;/code&gt; statement.&lt;/p&gt;

&lt;p&gt;Then, since our function now returns an iterator, we'll also have to handle that inside our for loop. In this case, instead of just calling our function again, we'll use another for loop to iterate through the iterator it returns. Each of the items in that loop will also be yielded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parse_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"asdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[[],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parse_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&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;foo
bar
asdf
34
1
2
3
4
5
6
7
True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could have done that with our previous function. However, we can also cast the iterator the function returns into a list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;parse_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;["foo", "bar", "asdf", 34, 1, 2, 3, 4, 5, 6, 7, True]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's modify the function so we can print a nicely formatted representation of the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;print_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s"&gt;"  "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;print_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&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;  foo
  bar
    asdf
    34
      1
      2
    3
    4
    5
    6
    7
  True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if our array also had dictionaries in it? What if it was a dictionary? We can add an &lt;code&gt;elif&lt;/code&gt; statement to handle that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parse_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parse_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To print a nicely formatted version of our array/dictionary, we could use this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;print_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s"&gt;"  "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;print_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s"&gt;"  "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"key1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"key2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="s"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5678&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;print_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&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;
key1:
  1

key2:
  1
  2

  foo:
    42

bar:

  a:
    1234

  b:
    5678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

&lt;p&gt;The combination of recursion and the &lt;code&gt;yield&lt;/code&gt; statement is pretty powerful. I'm definitely going to keep it in the back of my head when I'm programming.&lt;/p&gt;

&lt;p&gt;I hope you've also found this post to be helpful (or at least a little interesting).&lt;/p&gt;

&lt;p&gt;— jsimonrichard&lt;/p&gt;

&lt;p&gt;&lt;a href="https://repl.it/talk/share/Iterating-through-trees-using-the-yield-statement/86174"&gt;Repl IT Post&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>algorithms</category>
      <category>recursion</category>
    </item>
  </channel>
</rss>
