<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Barrett Otte</title>
    <description>The latest articles on Forem by Barrett Otte (@barrettotte).</description>
    <link>https://forem.com/barrettotte</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%2F128082%2F964e8682-759a-44bd-aaff-0e2ffad9d793.jpeg</url>
      <title>Forem: Barrett Otte</title>
      <link>https://forem.com/barrettotte</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/barrettotte"/>
    <language>en</language>
    <item>
      <title>Jupyter Notebooks + IBMi</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Wed, 06 May 2020 16:28:16 +0000</pubDate>
      <link>https://forem.com/barrettotte/jupyter-notebooks-ibmi-547g</link>
      <guid>https://forem.com/barrettotte/jupyter-notebooks-ibmi-547g</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6o1ba431mh8vjivphnis.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%2Fi%2F6o1ba431mh8vjivphnis.PNG" alt="pie"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is going to be a short post on calling basic IBMi DB2 statements from Jupyter Notebooks. It is really light on explanation, so I encourage googling terms you are not familiar with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Briefest Introduction to Jupyter
&lt;/h2&gt;

&lt;p&gt;Jupyter provides an environment for executing live code in a notebook like format. I find these especially useful for keeping "living notes" for mathematics and production support notes.&lt;/p&gt;

&lt;p&gt;A notebook consists of cells, which allow you to mix and match SQL, Markdown, Python, Javascript, and much more in the same notebook.&lt;/p&gt;

&lt;p&gt;Each cell can be executed independent of the other cells. So you can execute whatever cell you want.&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%2Fi%2F3ulob3e2bi2ubgbvcjju.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%2Fi%2F3ulob3e2bi2ubgbvcjju.PNG" alt="Jupyter Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a really basic example, but you can get the full power of pandas, numpy, matplotlib, etc to create some cool data visualizations. I won't be covering that because I'm pretty new to these modules still.&lt;/p&gt;

&lt;p&gt;Notebooks can be shared easily to other developers. &lt;br&gt;
When the notebook is committed to a repository, it includes all of the output for each cell (if they were executed).&lt;br&gt;
So, in a GitHub repository you can actually preview the notebook frozen in time.&lt;br&gt;
Its pretty neat, you'll see some cooler stuff here soon.&lt;/p&gt;

&lt;p&gt;I encourage you to go out and read more on Jupyter Notebooks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install dependencies -

&lt;code&gt;pip3 install jupyter pandas matplotlib numpy pyodbc&lt;/code&gt;

(Pyodbc is for my IBMi example)&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start Jupyter server -&lt;br&gt;
&lt;br&gt;
&lt;code&gt;jupyter notebook&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hosted locally at &lt;strong&gt;&lt;a href="http://localhost:8888/notebooks" rel="noopener noreferrer"&gt;http://localhost:8888/notebooks&lt;/a&gt;&lt;/strong&gt; by default&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why Pyodbc?
&lt;/h2&gt;

&lt;p&gt;So, I made this post because calling IBMi is a little funky to do from Python and Jupyter. Most SQL Jupyter examples you'll come across use a Python module called SQL Alchemy. This module provides some convenience functions for interacting with a database. &lt;/p&gt;

&lt;p&gt;The driver for IBMi access does not work with SQL Alchemy. There is a repository in progress to get it working, but I don't think its ready yet - &lt;a href="https://github.com/IBM/sqlalchemy-ibmi" rel="noopener noreferrer"&gt;https://github.com/IBM/sqlalchemy-ibmi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, that's okay we can still use the &lt;strong&gt;pyodbc&lt;/strong&gt; module.&lt;br&gt;
I won't go into a full example, but here is a link to my little eBook with an example program - &lt;a href="https://barrettotte.github.io/IBMi-Book/#/additional/call/python" rel="noopener noreferrer"&gt;https://barrettotte.github.io/IBMi-Book/#/additional/call/python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most important bit is in the connection string:&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;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pyodbc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{IBM i Access ODBC Driver}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's slightly different than a lot of the examples you'll find floating around for connecting to DB2 and was slightly annoying to figure out at first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small Utility Notebook
&lt;/h2&gt;

&lt;p&gt;To make it even easier to work with IBMi on Jupyter I made a little utility notebook at &lt;a href="https://github.com/barrettotte/IBMi-Jupyter" rel="noopener noreferrer"&gt;https://github.com/barrettotte/IBMi-Jupyter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It includes some utilities for connecting and displaying result sets.&lt;br&gt;
The main thing the utility notebook adds is some cell &lt;strong&gt;magic&lt;/strong&gt;.&lt;br&gt;
I won't go into too much detail, but it allows us to mark a cell to perform certain actions.&lt;/p&gt;

&lt;p&gt;I added cell &lt;strong&gt;magic&lt;/strong&gt; for DB2 for i. To mark a cell as DB2 for i, you include &lt;strong&gt;%%ibmi&lt;/strong&gt;, which pretty much tells Jupyter to treat this cell special with whatever is defined for ibmi magic. The cell magic I defined takes in a single flag and a series of SQL statements delimited by a semicolon.&lt;/p&gt;

&lt;p&gt;The SQL result set is returned as a &lt;strong&gt;pandas dataframe&lt;/strong&gt;. I encourage you to read up on them. To summarize, they are convenient data structures used in a lot of data science packages.&lt;/p&gt;

&lt;p&gt;Here is a summary of the flags I have currently implemented, they cause the cell magic to do things slightly different behind the scenes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;flag&lt;/th&gt;
&lt;th&gt;description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-csv&lt;/td&gt;
&lt;td&gt;result set as CSV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-html&lt;/td&gt;
&lt;td&gt;result set as HTML string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-json&lt;/td&gt;
&lt;td&gt;result set as JSON string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-tex&lt;/td&gt;
&lt;td&gt;result set as LaTex string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-str&lt;/td&gt;
&lt;td&gt;result set as simple string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-xml&lt;/td&gt;
&lt;td&gt;result set as XML string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-plotbar&lt;/td&gt;
&lt;td&gt;result set as simple bar graph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-plotpie&lt;/td&gt;
&lt;td&gt;result set as simple pie graph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-plotline&lt;/td&gt;
&lt;td&gt;result set as simple line graph&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Take a closer look at the cell magic in &lt;a href="https://github.com/barrettotte/IBMi-Jupyter/blob/master/IBMi.ipynb" rel="noopener noreferrer"&gt;https://github.com/barrettotte/IBMi-Jupyter/blob/master/IBMi.ipynb&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Examples (finally)
&lt;/h2&gt;

&lt;p&gt;To test out my utility notebook, I made a simple test notebook with a few queries.&lt;/p&gt;

&lt;p&gt;To include the utility notebook in another notebook, invoke it with&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;%run IBMi.ipynb&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 (or whatever path you put it).&lt;br&gt;
This will trigger the login, where it prompts for hostname, user, and password (kept as secret) using python inputs (getpass module for password).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Enter host: DEV400
Enter user: OTTEB
Enter password: ········
Connecting to DEV400 as OTTEB ...
Successfully connected!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every cell afterwards will have access to the connection.&lt;br&gt;
So let me show some example query screenshots, they are pretty self explanatory.&lt;br&gt;
I skipped the JSON, XML, etc string examples because they weren't as cool to show.&lt;/p&gt;

&lt;p&gt;All examples can be found in &lt;a href="https://github.com/barrettotte/IBMi-Jupyter/blob/master/tests/Test.ipynb" rel="noopener noreferrer"&gt;https://github.com/barrettotte/IBMi-Jupyter/blob/master/tests/Test.ipynb&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%2Fi%2F4x75fogthsci49gqhg8a.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%2Fi%2F4x75fogthsci49gqhg8a.PNG" alt="simple"&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%2Fi%2Fu9px5x1i78ahy7mi5kqu.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%2Fi%2Fu9px5x1i78ahy7mi5kqu.PNG" alt="src mbr list"&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%2Fi%2Fa9ndefiseltdayz066vm.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%2Fi%2Fa9ndefiseltdayz066vm.PNG" alt="src mbr"&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%2Fi%2Fbf2ih8ljth269289zpil.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%2Fi%2Fbf2ih8ljth269289zpil.PNG" alt="api"&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%2Fi%2Fi7sq2z3qu1n4lpk6pezo.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%2Fi%2Fi7sq2z3qu1n4lpk6pezo.PNG" alt="bar"&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%2Fi%2F6o1ba431mh8vjivphnis.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%2Fi%2F6o1ba431mh8vjivphnis.PNG" alt="pie"&gt;&lt;/a&gt;&lt;/p&gt;



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

&lt;p&gt;This utility notebook is pretty barebones right now. But, maybe it will give somebody some ideas on a fun project to start on. As I get bored over some lunches at work I intend to add in more flags and features to make this more powerful.&lt;/p&gt;

&lt;p&gt;The next thing I want to add is called &lt;strong&gt;Line Magic&lt;/strong&gt; so we can use the result set we get back from a query. At the same time, I will add in prepared statements to the existing magic, so more complex visualizations can be made.&lt;/p&gt;

&lt;p&gt;Feel free to yank the code for this and make something awesome.&lt;/p&gt;

&lt;p&gt;EDIT:&lt;br&gt;
I forgot to mention one of the other cool things. You can do all of this from VS Code as well. Jupyter Notebook support is bundled with the Python extension.&lt;br&gt;
This means you can also have a basic DB2 for i SQL client in the comfort of VS 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%2Fi%2Fqyapqyoydx5xsb3u4vhp.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%2Fi%2Fqyapqyoydx5xsb3u4vhp.PNG" alt="vscode"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jupyer</category>
      <category>python</category>
      <category>ibmi</category>
      <category>sql</category>
    </item>
    <item>
      <title>TRS80-Twilio, Sending Texts like its 1983!</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Tue, 28 Apr 2020 14:03:41 +0000</pubDate>
      <link>https://forem.com/barrettotte/trs80-twilio-sending-texts-like-its-1983-submission-450l</link>
      <guid>https://forem.com/barrettotte/trs80-twilio-sending-texts-like-its-1983-submission-450l</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Category Submission: Exciting X-Factors
&lt;/h4&gt;

&lt;p&gt;Send a text message from a TRS-80 Model 100 using the Twilio SMS API and an ESP8266.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The basic goal was to use a vintage computer as a frontend and an ESP8266 as a backend to send a text message&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5UkJfPM5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c6n0nas5ag08oz9qg182.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5UkJfPM5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c6n0nas5ag08oz9qg182.jpg" alt="TRS-80 Model 100" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As I state in my repository, &lt;strong&gt;In no way is this practical or should be recreated. This was solely for fun; don't take this too seriously.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I wanted to put the "HACK" in HACKATHON.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo Link
&lt;/h2&gt;

&lt;p&gt;An awful phone video showing this project in action with test credentials and "magic" test phone number. I figured it was better than nothing in case you wanted to see it actually running.&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=C2nngeuc3Oc"&gt;https://www.youtube.com/watch?v=C2nngeuc3Oc&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Link to Code
&lt;/h2&gt;

&lt;p&gt;Check out some of the additional documentation I included, as well as some small test programs. &lt;a href="https://github.com/barrettotte/TRS80-Twilio"&gt;https://github.com/barrettotte/TRS80-Twilio&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How I built it (what's the stack? did I run into issues or discover something new along the way?)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--466W2u5K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qle8nkqetupiza3cmaqm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--466W2u5K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qle8nkqetupiza3cmaqm.jpg" alt="TRS-80 Model 100" width="880" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend:&lt;/strong&gt; TRS-80 Model 100, BASIC&lt;br&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; ESP8266, Arduino platform, C++&lt;/p&gt;

&lt;p&gt;After I decided I was going to participate in the Twilio hackathon I stumbled across documentation for using an ESP8266 to send an SMS. Naturally, I decided to take it a step further and make a complete coding abomination.&lt;br&gt;
&lt;strong&gt;The basic goal was to use a vintage computer as a frontend and an ESP8266 as a backend to send a text message&lt;/strong&gt;.&lt;br&gt;
This probably won't get judged (I can't blame them), but this was one of the funnest projects I've ever done.&lt;/p&gt;

&lt;p&gt;I started out making the "frontend" on a TRS-80 Model 4P using BASIC and Z80 assembly. In order to write to the Model 4P's serial port, I had to embed Z80 machine language in BASIC. Example of embedding machine language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1   REM TEST EMBEDDED MACHINE LANGUAGE PROGRAM IN BASIC
10  DIM A%(12)
20  B = VARPTR(A%(0))
30  FOR I = 0 TO 11
40  READ C,D
50  E = D * 256 + C
60  IF E &amp;gt; 32767 THEN A%(I) = E - 65536 ELSE A%(I) = E
70  NEXT I
80  IF B &amp;gt; 32767 THEN DEFUSR0 = B - 65536 ELSE DEFUSR0 = B
90  X = USR0(0)
100 GOTO 90
105 REM ************* MACHINE LANGUAGE PGM *******************
110 DATA 33,64,60,17,0,60,1,192,3,237,176,33,192,63,62,32,6,64
120 DATA 119,35,16,252,201,0
125 REM ******************************************************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;I woke up one morning and my old computer no longer worked...Read more in my &lt;a href="https://github.com/barrettotte/TRS80-Twilio/tree/master/test/TRS80-4P"&gt;repo&lt;/a&gt;.&lt;br&gt;
I had no time to fix it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FJwLib41--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hnqzn4tgccr3u5azat0v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FJwLib41--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hnqzn4tgccr3u5azat0v.jpg" alt="TRS-80 Model 100" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I had to start from scratch 5 days before the due date of this hackathon.&lt;br&gt;
I recently bought a cheap TRS-80 model 100, so I switched over to learning how it worked.&lt;/p&gt;

&lt;p&gt;To my surprise, it was magnitudes easier to work with than the TRS-80 model 4P.&lt;br&gt;
With the model 4P, I was forced to embed Z80 machine code into BASIC in order to write to its serial port.&lt;br&gt;
With the model 100, all I had to do was open the serial port like a file and print to it...amazing.&lt;br&gt;
The primary frontend file is &lt;a href="https://github.com/barrettotte/TRS80-Twilio/blob/master/TWILIO.BAS"&gt;TWILIO.BAS&lt;/a&gt;.&lt;br&gt;
The frontend's job was to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provide a simple interface to input a phone number and message&lt;/li&gt;
&lt;li&gt;build a buffer of 145 bytes from user input&lt;/li&gt;
&lt;li&gt;basic phone number validation&lt;/li&gt;
&lt;li&gt;send buffer to the ESP8266 via RS232 (serial).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "backend" was pretty easy to build. I recently refreshed on Arduino and learned how to use PlatformIO.&lt;br&gt;
The biggest challenge with the backend was waiting for the incredibly slow serial port send all of the data. There was no good way to figure out when it was done. To solve this challenge, I decided to send a flat 145 bytes from the TRS-80 frontend each time. That way, I always knew that after reading 145 bytes I was done reading from the serial port.&lt;/p&gt;

&lt;p&gt;The primary backend file is &lt;a href="https://github.com/barrettotte/TRS80-Twilio/blob/master/src/main.cpp"&gt;src/main.cpp&lt;/a&gt;&lt;br&gt;
The backend's job was to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;establish connection to WiFi&lt;/li&gt;
&lt;li&gt;output helpful messages to OLED&lt;/li&gt;
&lt;li&gt;read serial input and parse buffer from TRS80&lt;/li&gt;
&lt;li&gt;establish connection to Twilio API&lt;/li&gt;
&lt;li&gt;build and invoke HTTP request to Twilio SMS API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, this was one of the funnest projects I've ever worked on.&lt;br&gt;
Truthfully, I wasn't sure if I was going to be able to pull this project off.&lt;br&gt;
The reward of hacking away and completing this was huge.&lt;/p&gt;

&lt;p&gt;Not to mention, I got to learn a lot about vintage computing and a bit about embedded development.&lt;/p&gt;
&lt;h2&gt;
  
  
  Project Layout
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ql-pZVG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q476i5v08mvduqx0tqgm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ql-pZVG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q476i5v08mvduqx0tqgm.png" alt="project layout" width="301" height="226"&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;### Basic Wiring ###

TRS80 DB25 --&amp;gt; DB25-DB9 Null Modem --&amp;gt; DB9 Male-Male --&amp;gt; TTL-RS232 ...

TTL-RS232   ESP8266      Mini OLED
              GND &amp;lt;----&amp;gt; GND
              3V3 &amp;lt;----&amp;gt; VCC
              D1  &amp;lt;----&amp;gt; SCL
              D2  &amp;lt;----&amp;gt; SDA
GND &amp;lt;-------&amp;gt; GND
VCC &amp;lt;-------&amp;gt; 3V3
TXD &amp;lt;-------&amp;gt; D6 (RXD)
RXD &amp;lt;-------&amp;gt; D5 (TXD)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Additional Resources/Info
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=0poh_2rBq7E"&gt;Introduction to PlatformIO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.classiccmp.org/dunfield/kyocera/index.htm"&gt;TRS-80 Model 100 Manuals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.trs-80.com/wordpress/"&gt;Ira Goldklang's TRS-80 Revived Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://manpages.ubuntu.com/manpages/trusty/man1/minicom.1.html"&gt;minicom manpages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.twilio.com/docs/sms/tutorials/how-to-send-sms-messages-esp8266-cpp"&gt;ESP9266 Twilio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>twiliohackathon</category>
      <category>trs80</category>
      <category>esp8266</category>
    </item>
    <item>
      <title>Sending a Text Message with SQL (IBMi)</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Thu, 23 Apr 2020 12:13:38 +0000</pubDate>
      <link>https://forem.com/barrettotte/sending-a-text-message-with-sql-ibmi-4jnj</link>
      <guid>https://forem.com/barrettotte/sending-a-text-message-with-sql-ibmi-4jnj</guid>
      <description>&lt;p&gt;This is going to be a pretty short post, but I thought it would be fun to share this in light of the Twilio + DEV hackathon this month. Honestly, I'm not sure if either project I planned out will be finished in time. This month went by way too fast, so the outlook is not good.&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with IBMi and have a few minutes to read, I encourage you to glance over a previous &lt;a href="https://dev.to/barrettotte/rpg-and-the-ibmi-563"&gt;subpar post&lt;/a&gt;. If not, it doesn't really matter; its not critical to looking at a couple blocks of SQL.&lt;/p&gt;

&lt;p&gt;This image is IBMi in a nutshell. It either disgusts or fascinates a younger developer; it is what it is.&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%2Fi%2F5nquzshf023ih32x2unx.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%2Fi%2F5nquzshf023ih32x2unx.png" alt="IBMi Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since I'm still a pretty new IBMi developer, I found that the best way to learn this new world was to take a fun idea and see if it was possible to do with &lt;a href="https://en.wikipedia.org/wiki/IBM_RPG" rel="noopener noreferrer"&gt;RPG&lt;/a&gt; and/or &lt;a href="https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/db2/rbafzintro.htm" rel="noopener noreferrer"&gt;DB2 SQL&lt;/a&gt;.&lt;br&gt;
Now I have a handful of arguably useless code snippets for my day job lol...&lt;/p&gt;
&lt;h2&gt;
  
  
  Example HTTP Request in DB2 for i
&lt;/h2&gt;

&lt;p&gt;One of the major things that made me fall in love with IBMi was that DB2 was really versatile. The fact that I could easily send HTTP requests with SQL was mind blowing.&lt;/p&gt;

&lt;p&gt;For a really basic example, I'm going to do a basic HTTP GET to the GitHub REST API v3 for my user using only SQL. The equivalent CURL command will be&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;
curl &lt;span class="nt"&gt;-i&lt;/span&gt; https://api.github.com/users/barrettotte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;This HTTP request is super simple because we don't need any HTTP headers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;values&lt;/span&gt; &lt;span class="n"&gt;SysTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpGetClob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://api.github.com/users/barrettotte'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="c1"&gt;-- url&lt;/span&gt;
  &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;clob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- http headers&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request returns&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;00001&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;'{"login":"barrettotte","id":15623775,"node_id"...}'&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;p&gt;Ok. That's cool because we can parse the JSON string in another program or something. But, actually we can do some way cooler stuff. We can return the HTTP response as a result set.&lt;/p&gt;

&lt;p&gt;Here is a really basic example, I mostly just used varchars for simplicity, but any field could be mapped to any appropriate data type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;json_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;SysTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpGetClob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://api.github.com/users/barrettotte'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;clob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s1"&gt;'$'&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;login&lt;/span&gt;          &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.login'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;             &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;node_id&lt;/span&gt;        &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.node_id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;avatar_url&lt;/span&gt;     &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.avatar_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;            &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;html_url&lt;/span&gt;       &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.html_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;followers_url&lt;/span&gt;  &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.followers_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;following_url&lt;/span&gt;  &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.following_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;gists_url&lt;/span&gt;      &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.gists_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;starred_url&lt;/span&gt;    &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.starred_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;subs_url&lt;/span&gt;       &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.subscriptions_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;orgs_url&lt;/span&gt;       &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.organizations_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;repos_url&lt;/span&gt;      &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.repos_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;events_url&lt;/span&gt;     &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.events_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;rcv_events_url&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.received_events_url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt;           &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;site_admin&lt;/span&gt;     &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.site_admin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;           &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;company&lt;/span&gt;        &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.company'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;blog&lt;/span&gt;           &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.blog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;location&lt;/span&gt;       &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.location'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;          &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.email'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;hireable&lt;/span&gt;       &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.hireable'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bio&lt;/span&gt;            &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.bio'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;public_repos&lt;/span&gt;   &lt;span class="nb"&gt;int&lt;/span&gt;           &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.public_repos'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;public_gists&lt;/span&gt;   &lt;span class="nb"&gt;int&lt;/span&gt;           &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.public_gists'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;followers&lt;/span&gt;      &lt;span class="nb"&gt;int&lt;/span&gt;           &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.followers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;following&lt;/span&gt;      &lt;span class="nb"&gt;int&lt;/span&gt;           &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.following'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt;     &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.created_at'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt;     &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.updated_at'&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request returns&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;LOGIN&lt;/th&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;NODE_ID&lt;/th&gt;
&lt;th&gt;...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;barrettotte&lt;/td&gt;
&lt;td&gt;15623775&lt;/td&gt;
&lt;td&gt;MDQ6VXN...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Personally I think this is really neat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calling Twilio from DB2 SQL
&lt;/h2&gt;

&lt;p&gt;I figured I should say I know that this is not an ideal solution for probably a majority of cases. But, this is just a fun thing I'm showing.&lt;/p&gt;

&lt;p&gt;The HTTP request I'm going to make looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST {{base}}/2010-04-01/Accounts/{{account}}/Messages.json HTTP/1.1
Authorization: Basic {{account}}:{{auth}}
Accept: application/json
Content-Type: application/x-www-form-urlencoded

To={{to}}&amp;amp;From={{from}}&amp;amp;Body=Hello+World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling Twilio takes a few more steps than the previous example. In DB2 for i, you have to pass HTTP headers as XML (I assume its a legacy thing and I wish it was JSON, but its still easy to work with). &lt;/p&gt;

&lt;p&gt;The authorization header has to be passed as a Base64 encoded string. There is a scalar function called &lt;strong&gt;Base64Encode&lt;/strong&gt; in &lt;strong&gt;SysTools&lt;/strong&gt; that seems to work fine.&lt;/p&gt;

&lt;p&gt;Additionally, Twilio wants the request body as a url-encoded string. To my surprise, I learned that &lt;strong&gt;SysTools&lt;/strong&gt; also has a scalar function called &lt;strong&gt;UrlEncode&lt;/strong&gt;. All of the hard work is done with scalar functions, you just have to piece them together.&lt;/p&gt;

&lt;p&gt;I replaced all &lt;strong&gt;secrets&lt;/strong&gt; in this query with 'variables' surrounded by double curly braces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;json_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;SysTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpPostClob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'https://api.twilio.com/2010-04-01/Accounts/{{account}}/Messages.json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;
      &lt;span class="s1"&gt;'&amp;lt;httpHeader&amp;gt;
        &amp;lt;header name="Authorization" value="Basic '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SysTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Base64Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'{{account}}:{{auth}}'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ccsid&lt;/span&gt; &lt;span class="mi"&gt;1208&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="s1"&gt;'"/&amp;gt;
        &amp;lt;header name="Accept" value="application/json"/&amp;gt;
        &amp;lt;header name="Content-Type" value="application/x-www-form-urlencoded"/&amp;gt;
      &amp;lt;/httpHeader&amp;gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;clob&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;
      &lt;span class="s1"&gt;'To='&lt;/span&gt;    &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;SysTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UrlEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'{{to}}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'UTF-8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="s1"&gt;'&amp;amp;From='&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;SysTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UrlEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'{{from}}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'UTF-8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="s1"&gt;'&amp;amp;Body='&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;SysTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UrlEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Hello World'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'UTF-8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;clob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s1"&gt;'$'&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sid&lt;/span&gt;           &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.sid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;date_created&lt;/span&gt;  &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.date_created'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;date_updated&lt;/span&gt;  &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.date_updated'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;date_sent&lt;/span&gt;     &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.date_sent'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;account_sid&lt;/span&gt;   &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.account_sid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;phone_to&lt;/span&gt;      &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.to'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;phone_from&lt;/span&gt;    &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.from'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;msg_srv_sid&lt;/span&gt;   &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.messaging_service_sid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;          &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.body'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;        &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.status'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;num_segments&lt;/span&gt;  &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.num_segments'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;num_media&lt;/span&gt;     &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.num_media'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;direction&lt;/span&gt;     &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.direction'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_version&lt;/span&gt;   &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.api_version'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;         &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.price'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price_unit&lt;/span&gt;    &lt;span class="nb"&gt;varchar&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="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.price_unit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;error_code&lt;/span&gt;    &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.error_code'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;error_message&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.error_message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;uri&lt;/span&gt;           &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.uri'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;nested&lt;/span&gt; &lt;span class="s1"&gt;'$.subresource_uris[*]'&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;media&lt;/span&gt;       &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="s1"&gt;'lax $.media'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request returns&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SID&lt;/th&gt;
&lt;th&gt;DATE_CREATED&lt;/th&gt;
&lt;th&gt;DATE_UPDATED&lt;/th&gt;
&lt;th&gt;DATE_SENT&lt;/th&gt;
&lt;th&gt;ACCOUNT_SID&lt;/th&gt;
&lt;th&gt;PHONE_TO&lt;/th&gt;
&lt;th&gt;...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;Wed, 22 Apr 2020 23:35:26 +0000&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;That's kind of it, I thought it was pretty cool and figured I'd share it for anyone browsing around this morning.&lt;br&gt;
The gist can be found &lt;a href="https://gist.github.com/barrettotte/8a12130d40882c52a18c14f9a72df12a" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Realistically, I don't know what you would do with this. But, knowing that it exists "might" do some good in some situation.&lt;/p&gt;

</description>
      <category>ibmi</category>
      <category>sql</category>
      <category>twiliohackathon</category>
    </item>
    <item>
      <title>Writing an IBMi Syntax Highlighter for VS Code</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Mon, 30 Mar 2020 13:22:18 +0000</pubDate>
      <link>https://forem.com/barrettotte/writing-an-ibmi-syntax-highlighter-for-vs-code-4h0j</link>
      <guid>https://forem.com/barrettotte/writing-an-ibmi-syntax-highlighter-for-vs-code-4h0j</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wduFdpiM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/barrettotte/vscode-ibmi-languages/master/screenshots/rpglefixed.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wduFdpiM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/barrettotte/vscode-ibmi-languages/master/screenshots/rpglefixed.PNG" alt="RPGLE Fixed" width="880" height="649"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I love VS Code and really want it to be the "all in one" editor.&lt;br&gt;
Unfortunately, there are still plenty of fringe cases that just don't work yet.&lt;/p&gt;

&lt;p&gt;To make a long stort short, I recently started working as an IBMi developer. Its a &lt;strong&gt;midrange system&lt;/strong&gt; (the middle ground between standard server and mainframe) that uses an old programming language called &lt;strong&gt;RPG&lt;/strong&gt; (&lt;a href="https://en.wikipedia.org/wiki/IBM_RPG"&gt;https://en.wikipedia.org/wiki/IBM_RPG&lt;/a&gt;, the same era as COBOL and FORTRAN).&lt;br&gt;
So, I decided I wanted to be able to use VS Code to read IBMi code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Time to Learn Regular Expressions
&lt;/h2&gt;

&lt;p&gt;A couple months ago I didn't know the black magic behind regular expressions.&lt;br&gt;
In a prior side project (&lt;a href="https://github.com/barrettotte/Ranger-Lang"&gt;https://github.com/barrettotte/Ranger-Lang&lt;/a&gt;) I learned about compiler theory and finite automata. &lt;br&gt;
Which cleared the fog on the reasons why regular expressions exist and a bit of the syntax. I highly suggest taking a bit of time to read through some basic examples of finite automata to get a sense of what I'm talking about.&lt;/p&gt;

&lt;p&gt;The rest of my learning was messing around for literal hours using &lt;a href="https://regexr.com/"&gt;https://regexr.com/&lt;/a&gt; . This tool saved my life, it made things so easy to test.&lt;/p&gt;

&lt;p&gt;Yes, it took me that long to get the hang of things; you have to be willing to put in the time when you're as dumb as me.&lt;/p&gt;
&lt;h2&gt;
  
  
  Regular Expression Lookaround
&lt;/h2&gt;

&lt;p&gt;One of the most valuable things to know how to do in regular expressions is lookaround.&lt;br&gt;
A key concept to understand in regular expressions is that once a pattern is matched, the characters matched are "eaten" by the regex engine (they cannot be reused).&lt;br&gt;
A lookaround allows you to match a pattern ahead or behind and does not consume the characters matched.&lt;/p&gt;
&lt;h2&gt;
  
  
  Regular Expression Example
&lt;/h2&gt;

&lt;p&gt;For example,&lt;br&gt;
I had to make sure there was an 'F' in column 6, an 'F' or 'E' in column 14, and a certain set of words in column 41.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     FPRINTER O   F     132     OF     PRINTER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using positive lookbehind, I can check the 'F', the 'F' or 'E', and 'PRINTER' while ensuring that all conditions are matched.&lt;/p&gt;

&lt;p&gt;REGEX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(?i)(?&amp;lt;=(?&amp;lt;=(?&amp;lt;=^[\s]{5}F).{8}).{4}(F|E).{20})(WORKSTN|DISK|PRINTER|SPECIAL|SEQ)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This regex will lookbehind for two conditions and match a word (WORKSTN...SEQ) if the prior conditions are matched.&lt;/p&gt;

&lt;p&gt;Broken down this is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(?i)               // case insensitive switch
(?&amp;lt;=               // start outer positive lookbehind
  (?&amp;lt;=             // start middle positive lookbehind 
    (?&amp;lt;=           // start inner positive lookbehind
      ^            // beginning of string
      [\s]{5}      // any non-whitespace character 5 times
      F            // 'F'
    )              // end inner positive lookbehind
    .{8}           // any character 8 times
  )                // end middle positive lookbehind
.{4}               // any character 4 times
(F|E)              // match either 'F' or 'E'
.{20}              // any character 20 times
)                  // end outer positive lookbehind
(WORKSTN|...|SEQ)  // match any word in list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At least for me, this didn't make much sense until I got my hands dirty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to TextMate
&lt;/h2&gt;

&lt;p&gt;Atom and VS Code both use a thing called &lt;strong&gt;TextMate&lt;/strong&gt; to handle all syntax highlighting. It provides a convenient way to list out sets of regular expressions that correspond to parts of a language such as constants, functions, keywords, operators, etc.&lt;/p&gt;

&lt;p&gt;Googling around it seems that the TextMate grammars can be written in XML, JSON, and YML. I decided on JSON after screwing around with the YML version and not getting it working correctly (I think).&lt;/p&gt;

&lt;p&gt;The previous regular expression example as a TextMate Grammar; I make (WORKSTN|...|SEQ) highlight as&lt;br&gt;
a constant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"constants"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"patterns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"constant.language.rpg.f.device"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(?i)(?&amp;lt;=(?&amp;lt;=(?&amp;lt;=^[&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;s]{5}F).{8}).{4}(F|E).{20})(WORKSTN|DISK|PRINTER|SPECIAL|SEQ)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also a lot more fancy things you can do with nested patterns, but I won't get into it here. If you're curious read more at &lt;a href="https://www.apeth.com/nonblog/stories/textmatebundle.html"&gt;https://www.apeth.com/nonblog/stories/textmatebundle.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For fun, here's a link to Dart's syntax highlighter in TextMate &lt;a href="https://github.com/Dart-Code/Dart-Code/blob/master/syntaxes/dart.json"&gt;https://github.com/Dart-Code/Dart-Code/blob/master/syntaxes/dart.json&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  VS Code Language Extension
&lt;/h2&gt;

&lt;p&gt;Another reason why I love VS Code is that they provide just enough documentation to get you started and let you go off on your own.&lt;/p&gt;

&lt;p&gt;Language extensions are no exception, I just used this documentation page to get started &lt;a href="https://code.visualstudio.com/api/language-extensions/overview"&gt;https://code.visualstudio.com/api/language-extensions/overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything else was achieved by looking around at existing extensions and screwing around with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Using the basic knowledge I wrote above, I sat down one week and just kept hacking away.&lt;/p&gt;

&lt;p&gt;For my particular extension, I sat down reading IBM's language documentation and making regex one piece at a time.&lt;br&gt;
By the end of it I made my language extension support DDS, RPG, RPGLE (fixed and free formats), Control Language (CL), and Machine Interface (MI).&lt;br&gt;
You can check out my extension at &lt;a href="https://github.com/barrettotte/vscode-ibmi-languages"&gt;https://github.com/barrettotte/vscode-ibmi-languages&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Honestly, its not that hard of work its just insanely tedious and time consuming. But if you don't know how regular expressions really work, here is the perfect excuse to learn.&lt;/p&gt;

&lt;p&gt;This is also the perfect weekend project to put on some music, drink some beer, and be a tiny bit productive while not working too hard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--usy7gFFx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/barrettotte/vscode-ibmi-languages/master/screenshots/rpglefree.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--usy7gFFx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/barrettotte/vscode-ibmi-languages/master/screenshots/rpglefree.PNG" alt="RPGLE Free" width="880" height="786"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>extension</category>
      <category>ibmi</category>
      <category>rpgle</category>
    </item>
    <item>
      <title>IBM i "Book" Chapters 1 and 2</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Thu, 10 Oct 2019 14:02:39 +0000</pubDate>
      <link>https://forem.com/barrettotte/ibmi-book-chapters-1-and-2-40ij</link>
      <guid>https://forem.com/barrettotte/ibmi-book-chapters-1-and-2-40ij</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bHIq2tjO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/c6f51nssiylzsvrn5wwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bHIq2tjO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/c6f51nssiylzsvrn5wwl.png" alt="Alt Text" width="880" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a post to say that I have "completed" the first two chapters of my small "book" &lt;strong&gt;Learning IBM i as a Lowly Web Developer&lt;/strong&gt;. (Most of the core content is in an acceptable state, but may still be tweaked when I read it over for the millionth time).&lt;/p&gt;

&lt;p&gt;The work in progress can be found at &lt;a href="https://barrettotte.github.io/IBMi-Book/#/"&gt;https://barrettotte.github.io/IBMi-Book/#/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;It should be obvious, but I'm not a writer and barely a programmer sometimes.&lt;br&gt;
This book is lazy and heavily relies on "learning by example". Therefore, it might be tough for some people to follow. But, I do try to briefly explain and walkthrough writing each program.&lt;/p&gt;

&lt;p&gt;I also decided to use SEU throughout this book just to get the full "green screen" experience. If you can code in SEU, you can code in something better be default.&lt;/p&gt;

&lt;p&gt;I do mention &lt;a href="https://github.com/worksofbarry/ILEditor"&gt;ILEditor&lt;/a&gt; and plan to include a brief overview of this awesome IDE so that people have the option to use it instead of ancient SEU.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 1
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://barrettotte.github.io/IBMi-Book/#/core/ibmi/index"&gt;https://barrettotte.github.io/IBMi-Book/#/core/ibmi/index&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In chapter 1, I mainly go over operating system concepts and Access Client Solutions (ACS). This includes some Source Entry Utility (SEU) and Program Development Manager (PDM).&lt;/p&gt;

&lt;p&gt;For practice, I walkthrough creating a library, source physical file, and a CL source member. Additionally, I step through compiling and running a three line CL program.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chapter 2
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://barrettotte.github.io/IBMi-Book/#/core/cl/index"&gt;https://barrettotte.github.io/IBMi-Book/#/core/cl/index&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In chapter 2, I give an overview of the syntax/structure of CL and start writing some basic CL. The example CL program I provided accepts user input via inquiry and echos it back to the user as a message.&lt;/p&gt;

&lt;p&gt;For a more beefy example, I included a subpar implementation of fizzbuzz in CL to go over subroutines, conditionals, and loops. It could definitely be a better implementation, but I think it serves its purpose just fine.&lt;/p&gt;

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

&lt;p&gt;I hope to keep making progress on this book as I feel inspired. The next chapter is going to be on the basics of some old RPG and newer RPGLE. Additionally, I hope to add more content to the CL chapter on the differences between newer CLLE vs CL.&lt;/p&gt;

&lt;p&gt;If you happen to read the book and have a suggestion on an improvement, please open an issue in my repository here &lt;a href="https://barrettotte.github.io/IBMi-Book/#/"&gt;https://barrettotte.github.io/IBMi-Book/#/&lt;/a&gt; and I'll definitely consider it. After all, I'm still a complete noob to the IBMi and could use all the help I can get.&lt;/p&gt;

&lt;p&gt;On a related note, my company allowed me to attend &lt;a href="https://www.systemideveloper.com/summit/conferences.html"&gt;RPG &amp;amp; DB2 Summit&lt;/a&gt; in Minneapolis. I'm 23 so I'll be sticking out like a sore thumb around all the seasoned IBM i developers. I hope to learn a bunch of cool content to include/mention in this book.&lt;/p&gt;

</description>
      <category>ibmi</category>
      <category>rpgle</category>
      <category>as400</category>
      <category>rpg</category>
    </item>
    <item>
      <title>Coding Abomination: Conway's Game of Life in TSQL</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Sun, 22 Sep 2019 21:08:53 +0000</pubDate>
      <link>https://forem.com/barrettotte/coding-abomination-conway-s-game-of-life-in-tsql-40fd</link>
      <guid>https://forem.com/barrettotte/coding-abomination-conway-s-game-of-life-in-tsql-40fd</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxp3gxl21eax9a8pg04hg.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fxp3gxl21eax9a8pg04hg.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GIF can be seen here&lt;br&gt;
&lt;a href="https://github.com/barrettotte/SQL-Game-of-Life/blob/master/demo.gif" rel="noopener noreferrer"&gt;https://github.com/barrettotte/SQL-Game-of-Life/blob/master/demo.gif&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One morning during my commute I was zoning out and realized I wanted to make a really dumb side project in SQL. One of my favorite things to do is use a language unconventionally and I thought implementing Game of Life was the perfect little project to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Game of Life
&lt;/h2&gt;

&lt;p&gt;If you are unfamiliar with Conway's Game of Life, I encourage to read more about it here &lt;a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The "algorithm" it uses is very simple. For each cell (pixel) in the environment (board), there are 4 rules for determining the next generation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Any live cell with fewer than two live neighbours dies, as if by underpopulation.&lt;/li&gt;
&lt;li&gt;Any live cell with two or three live neighbours lives on to the next generation.&lt;/li&gt;
&lt;li&gt;Any live cell with more than three live neighbours dies, as if by overpopulation.&lt;/li&gt;
&lt;li&gt;Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Taken from the previously linked wiki page)&lt;/p&gt;

&lt;p&gt;Through these simple rules, "organisms" can appear that exhibit different behavior. In my example, I implement a "blinker" and a "glider". They can also be found on the wiki page I linked.&lt;/p&gt;

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

&lt;p&gt;For this project I could have used TSQL's built in PRINT function, but I wanted actual animation. To do this, I would have to leverage a little bit of Python to display the data that my stored procedure produced using the stdout buffer.&lt;/p&gt;

&lt;p&gt;The stored procedure I made stores the cell data of each generation. If I take the cell data for each generation I can feed it into a drawing function to represent each frame in an animation.&lt;/p&gt;

&lt;p&gt;Now, I will say the stored procedure runs terribly. But, &lt;strong&gt;the goal was to get a basic glider to travel across the screen&lt;/strong&gt;. I am 100% sure I could have done some fancy JOINs or something. But, I just ended up using SQL like a general purpose language instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source
&lt;/h2&gt;

&lt;p&gt;The project consisted of a single stored procedure and a python display script.&lt;br&gt;
Everything can be found here &lt;a href="https://github.com/barrettotte/SQL-Game-of-Life" rel="noopener noreferrer"&gt;https://github.com/barrettotte/SQL-Game-of-Life&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding Abominations
&lt;/h2&gt;

&lt;p&gt;Its all well and good to spend your time programming useful things or learning new subjects. But, I think one of the funnest things to do is make really obscure and useless projects.&lt;/p&gt;

&lt;p&gt;You would be surprised on how much you learn when making something super bizarre that has been implemented by only a few people. It forces you to think outside the box and touch parts of a language that you don't normally handle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I find that making a coding abomination every once in a while is a good anti-burnout exercise&lt;/strong&gt;. After finishing a fun coding abomination, I feel refreshed to tackle another side project. The important thing is to pick something you're relatively interested in, otherwise you're not going to have a good time.&lt;/p&gt;

&lt;p&gt;Another fun abomination I made a few months back was a 2D perlin noise SVG generator using only XSLT &lt;a href="https://github.com/barrettotte/XSLT-Perlin2D" rel="noopener noreferrer"&gt;https://github.com/barrettotte/XSLT-Perlin2D&lt;/a&gt; . &lt;br&gt;
I ended up learning a bunch of neat tricks in XSLT that I didn't even know were possible.&lt;/p&gt;

</description>
      <category>tsql</category>
      <category>sql</category>
      <category>python</category>
      <category>gameoflife</category>
    </item>
    <item>
      <title>Write a Book with Docsify</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Mon, 16 Sep 2019 12:24:23 +0000</pubDate>
      <link>https://forem.com/barrettotte/write-a-book-with-docsify-3c0o</link>
      <guid>https://forem.com/barrettotte/write-a-book-with-docsify-3c0o</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq7pt4f8hbv99s9unzcf8.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq7pt4f8hbv99s9unzcf8.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you ever thought about writing a small book in the comfort of markdown/html then I would suggest using Docsify; &lt;a href="https://github.com/docsifyjs/docsify" rel="noopener noreferrer"&gt;https://github.com/docsifyjs/docsify&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docsify is pretty intuitive and has sufficient documentation to get you through the basics of putting together a book. Each directory is a section&lt;br&gt;
and each markdown file is a page in the book. It also has other features such as navigation, cover pages, and sidebars that I haven't dove too deep into.&lt;/p&gt;

&lt;p&gt;Since it uses markdown, you can also use standard HTML and CSS to style everything. I've had mixed results, but it seems like you can also use basic JavaScript as well. The only catch I've found so far is that you cannot use any asynchronous content. For example, I was unable to use embedded code snippets from &lt;a href="https://www.cacher.io/" rel="noopener noreferrer"&gt;https://www.cacher.io/&lt;/a&gt; since it is an asynchronous request to cacher to get the content.&lt;/p&gt;
&lt;h2&gt;
  
  
  Commands
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install docsify cli through npm - &lt;strong&gt;npm i -g docsify-cli&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Start a new project - &lt;strong&gt;docsify init mybook&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Serve book locally on &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; - &lt;strong&gt;docsify serve mybook&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Sample Page
&lt;/h2&gt;

&lt;p&gt;As expected, you can mix and match markdown and HTML depending on what you need to do. For all of my cases, this was perfect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Sample page from my book --&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Introduction to the 5250 Emulator&lt;/span&gt;

This is an emulator of the IBM 5250 terminal originally used to interact with the IBMi and its ancestors. A bit more information on it here https://en.wikipedia.org/wiki/IBM_5250

There's a lot of features in this emulator that I haven't messed around with.

One important thing I learned is using the &lt;span class="gs"&gt;**popup keypad**&lt;/span&gt; located in &lt;span class="gs"&gt;**Actions**&lt;/span&gt; &amp;gt; &lt;span class="gs"&gt;**Popup Keypad...**&lt;/span&gt;
Sometimes when things go wrong, you have to use &lt;span class="gs"&gt;**SysReq**&lt;/span&gt; to bail yourself out (more on this later).
&lt;span class="nt"&gt;&amp;lt;figure&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./core/ibmi/_assets/5250-01.PNG"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Popup Keypad"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/figure&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code Blocks
&lt;/h2&gt;

&lt;p&gt;One feature I wanted in my book was basic code blocks with a dark theme. Docsify uses a syntax highlighting package called &lt;a href="https://github.com/PrismJS/prism" rel="noopener noreferrer"&gt;Prism JS&lt;/a&gt;. For the most part, Prism JS works pretty well out of the box. To include syntax highlighting for PHP you would throw this into your &lt;strong&gt;index.html&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"//unpkg.com/prismjs/components/prism-php.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, I wasn't smart enough to figure out how to use the Prism plugin with Docsify (if you even can). I also tried to get line numbers working through a couple different CSS snippets, but I think my frontend abilities are severely lacking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Blocks with Monokai Theme
&lt;/h2&gt;

&lt;p&gt;Additionally, I wanted to implement a dark theme like Monokai in VS Code.&lt;br&gt;
I found a theme called &lt;strong&gt;Xonokai&lt;/strong&gt; that was close enough to what I wanted&lt;br&gt;
&lt;a href="https://github.com/PrismJS/prism-themes" rel="noopener noreferrer"&gt;https://github.com/PrismJS/prism-themes&lt;/a&gt; . I also created a basic &lt;strong&gt;styles.css&lt;/strong&gt; to do some additional tweaking on the Xonokai theme.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/*styles.css*/&lt;/span&gt;

&lt;span class="c"&gt;/* Hide php tag in code block */&lt;/span&gt;
&lt;span class="nf"&gt;#main&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;pre&lt;/span&gt;&lt;span class="nd"&gt;::after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="nf"&gt;#main&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;pre&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;#main&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#2e2e2e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;#main&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;pre&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.sidebar&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.sidebar-toggle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;228&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;228&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;228&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As expected, you can link stylesheets in your &lt;strong&gt;index.html&lt;/strong&gt;. I put all of my css in a root directory &lt;strong&gt;_assets/css&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"./_assets/css/prism-xonokai.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"./_assets/css/styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Currently, this is what it looks like when its all said and done&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F3yrqd792b7r330q077dj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F3yrqd792b7r330q077dj.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Additional Setup
&lt;/h2&gt;

&lt;p&gt;I haven't gone super deep into docsify, but I've found a few cool things.&lt;br&gt;
There's a pretty sweet plugin for pagination within chapters that can be added using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"//unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lot of customizing can be done within the &lt;strong&gt;window.$docsify&lt;/strong&gt; element, here is my configuration that includes a homepage, repo link, and sidebar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$docsify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://github.com/barrettotte/IBMi-Book&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;loadSidebar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/.*/_sidebar.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/_sidebar.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;homepage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;README.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;auto2top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is really just scratching the surface, but you can find much more at &lt;a href="https://docsify.js.org/#/?id=docsify" rel="noopener noreferrer"&gt;https://docsify.js.org/#/?id=docsify&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying to GitHub Pages
&lt;/h2&gt;

&lt;p&gt;If you put all of your book content within a &lt;strong&gt;docs&lt;/strong&gt; directory of your repository, you can use your repository as a GitHub.io page with ease. To make sure that your repository isn't mistaken for a Jekyll site, create an empty file named &lt;strong&gt;.nojekyll&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To enable the GitHub.io page go to your GitHub repository and select &lt;strong&gt;master branch /docs folder&lt;/strong&gt; in &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;GitHub Pages&lt;/strong&gt; &amp;gt; &lt;strong&gt;Source&lt;/strong&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjc1feaz3cavvwywu1dov.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjc1feaz3cavvwywu1dov.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My "Book"
&lt;/h2&gt;

&lt;p&gt;I hesitate to call what I'm making a book, but you can find my project &lt;strong&gt;Learning the IBMi as a Lowly Web Developer&lt;/strong&gt; at &lt;a href="https://barrettotte.github.io/IBMi-Book/#/" rel="noopener noreferrer"&gt;https://barrettotte.github.io/IBMi-Book/#/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will be a beginner's guide to programming on the IBMi with RPGLE, CL, and more. I hope to stay motivated/focused and keep chipping away at it.&lt;/p&gt;

&lt;p&gt;Thanks for reading this post.&lt;/p&gt;

</description>
      <category>docsify</category>
      <category>markdown</category>
      <category>book</category>
    </item>
    <item>
      <title>Simple Util to Pull Code From IBM i</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Mon, 19 Aug 2019 15:38:42 +0000</pubDate>
      <link>https://forem.com/barrettotte/simple-util-to-pull-code-from-the-ibmi-5hfp</link>
      <guid>https://forem.com/barrettotte/simple-util-to-pull-code-from-the-ibmi-5hfp</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cFYzor63--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0beve1mrakul3idi2avo.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cFYzor63--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0beve1mrakul3idi2avo.PNG" alt="Alt Text" width="880" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In one of my really dumb side projects I'm making, I have some IBM i code that I'd like to keep in my git repository with some other stuff. I could use the Integrated File System (IFS), but truthfully I don't know enough about IBM i yet to use it correctly.&lt;/p&gt;

&lt;p&gt;So, in the meantime I have a quick and dirty python script that lets me pull multiple source members based on a config file, repo.json. This isn't the cleanest, but it works pretty well.&lt;/p&gt;

&lt;p&gt;My repo.json is very basic, but lays out a basic IBM i file structure to loop over below with FTP&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"library"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BOLIB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"spfs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"QRPGLESRC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"extension"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RPGLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"members"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FIZZBUZZ"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic Idea
&lt;/h2&gt;

&lt;p&gt;If you connect to IBM i over SSH you can navigate and find your source members. For example, I'm going to drill down into my QRPGLESRC file within my BOLIB library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bb6K8MDi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/53fqzua58t0iuc0c56ah.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bb6K8MDi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/53fqzua58t0iuc0c56ah.PNG" alt="Alt Text" width="880" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, there are my QRPGLESRC members hanging out. All my script does is automate grabbing the source members.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;To start, I use a few basic modules found in the python standard library.&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ftplib&lt;/span&gt;  &lt;span class="c1"&gt;# easily setup FTP connection
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;    &lt;span class="c1"&gt;# read in repo.json config file
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;getpass&lt;/span&gt; &lt;span class="c1"&gt;# used to discretely get password
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;      &lt;span class="c1"&gt;# used to safely make directories for output
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I load my config file, instantiate my FTP client, and get the hostname, username, and password from the console&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;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./repo.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ftp_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ftplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FTP&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter Host: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter User: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter Password: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# FTP logic below...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, I setup my FTP connection shell with very basic error handling&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;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;ftp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;ftp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# The meat of the code here ...
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ftplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_errors&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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="s"&gt;"Error occurred with FTP.&lt;/span&gt;&lt;span class="se"&gt;\n&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;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nb"&gt;exit&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="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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="s"&gt;"Some other error occurred&lt;/span&gt;&lt;span class="se"&gt;\n&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;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nb"&gt;exit&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="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;ftp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the fun stuff, sending FTP RETR command to get data from IBM i&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;lib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'library'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# my example only has one library, so no looping
&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'spfs'&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="s"&gt;"Fetching member(s) from {}/{}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'./'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt; 
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# make a directory based on source physical file name
&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mbr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'members'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
      &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

      &lt;span class="c1"&gt;# The magic command to get data  ex: BOLIB/QRPGLESRC/FIZZBUZZ.mbr
&lt;/span&gt;      &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"RETR {}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/QSYS.lib/{}.lib/{}.file/{}.mbr"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;mbr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

      &lt;span class="n"&gt;ftp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retrlines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# run the command
&lt;/span&gt;
      &lt;span class="c1"&gt;# Create file based on specified extension ex: RPGLE
&lt;/span&gt;      &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'/'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mbr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'.'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'extension'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="c1"&gt;# Finally, write data to file
&lt;/span&gt;      &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w+'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&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;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&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;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;'&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="s"&gt;"  Saved "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ftplib&lt;/span&gt;  &lt;span class="c1"&gt;# easily setup FTP connection
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;    &lt;span class="c1"&gt;# read in repo.json config file
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;getpass&lt;/span&gt; &lt;span class="c1"&gt;# used to discretely get password
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;      &lt;span class="c1"&gt;# used to safely make directories for output
&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./repo.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ftp_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ftplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FTP&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter Host: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter User: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter Password: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;ftp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;ftp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;lib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'library'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# my example only has one library, so no looping
&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'spfs'&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="s"&gt;"Fetching member(s) from {}/{}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'./'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt; 
      &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# make a directory based on source physical file name
&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;mbr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'members'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
      &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

      &lt;span class="c1"&gt;# The magic command to get data  ex: BOLIB/QRPGLESRC/FIZZBUZZ.mbr
&lt;/span&gt;      &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"RETR {}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/QSYS.lib/{}.lib/{}.file/{}.mbr"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;mbr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

      &lt;span class="n"&gt;ftp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retrlines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# run the command
&lt;/span&gt;
      &lt;span class="c1"&gt;# Create file based on specified extension ex: RPGLE
&lt;/span&gt;      &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'/'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mbr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'.'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;spf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'extension'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="c1"&gt;# Finally, write data to file
&lt;/span&gt;      &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w+'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&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;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&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;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;'&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="s"&gt;"  Saved "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ftplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_errors&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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="s"&gt;"Error occurred with FTP.&lt;/span&gt;&lt;span class="se"&gt;\n&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;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nb"&gt;exit&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="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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="s"&gt;"Some other error occurred&lt;/span&gt;&lt;span class="se"&gt;\n&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;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="nb"&gt;exit&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="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;ftp_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The File was Fetched!
&lt;/h2&gt;

&lt;p&gt;This is stored in ./QRPGLESRC/FIZZBUZZ.RPGLE&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;       &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;free&lt;/span&gt;
       &lt;span class="c1"&gt;// The classic fizzbuzz program in RPGLE Free&lt;/span&gt;
       &lt;span class="n"&gt;dcl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

       &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&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;to&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nf"&gt;REM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&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;and&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nf"&gt;REM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="nf"&gt;dsply&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'num - '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nf"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;' FIZZBUZZ'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nf"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="nf"&gt;dsply&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'num - '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nf"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;' FIZZ'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nf"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="nf"&gt;dsply&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'num - '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nf"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;' BUZZ'&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="nf"&gt;dsply&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'num - '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nf"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
           &lt;span class="k"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="k"&gt;endfor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;INLR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="no"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Simple Batch script
&lt;/h2&gt;

&lt;p&gt;In my repository, I made a little batch script so I could pull IBM i code and commit it with the rest of my repository in one call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@ECHO OFF
IF &lt;span class="o"&gt;[&lt;/span&gt;%1] &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt; GOTO NOMSG
python ibmi-pull.py &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;"%~1"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push origin master
GOTO END
:NOMSG
  ECHO &lt;span class="s2"&gt;"Enter the commit message!"&lt;/span&gt;
:END
PAUSE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, there's probably some better "tools" you could make involving the IFS, but I'm just not there yet knowledge-wise.&lt;/p&gt;

&lt;p&gt;As an experiment, I expanded upon this simple script to grab an entire library and generate a basic git repository : &lt;br&gt;
&lt;a href="https://github.com/barrettotte/IBMi-Lib-Repo"&gt;https://github.com/barrettotte/IBMi-Lib-Repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ibmi</category>
      <category>rpgle</category>
      <category>as400</category>
    </item>
    <item>
      <title>RPG and IBM i</title>
      <dc:creator>Barrett Otte</dc:creator>
      <pubDate>Fri, 02 Aug 2019 16:43:46 +0000</pubDate>
      <link>https://forem.com/barrettotte/rpg-and-the-ibmi-563</link>
      <guid>https://forem.com/barrettotte/rpg-and-the-ibmi-563</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0kjxzu87dygrr1f338ji.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0kjxzu87dygrr1f338ji.PNG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is my first post to DEV to see if there are any developers on here who have messed around with IBM i before or are interested in learning what it is. Primarily, I will be focusing on the history of IBM i and the RPG programming language that has evolved with it.&lt;/p&gt;

&lt;p&gt;At my current workplace, I noticed this ominous green and black screen on numerous older developers' monitors. Shortly after, I found out that my company develops and maintains an IBM i system with an RPG(LE) codebase. I was immediately intrigued and set out to learn what was happening. The problem is that learning a new paradigm of thinking is difficult.&lt;/p&gt;

&lt;p&gt;Since I was a web developer and expressed a bit of interest in learning IBM i, I was given a user account and library that I could mess around with. I searched around various sites and some IBM documentation for a "tutorial". But, I quickly learned that there really isn't too great of a starting point compared to learning every other programming language and/or OS.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Important Lesson
&lt;/h2&gt;

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

&lt;p&gt;If you ever find yourself wanting to learn RPG by purchasing a used AS/400 on eBay, don't do it (unless you have an additional $20K). IBM is cool, but their software is expensive and closed source. So, I have a pretty sweet 500lb bar table in my basement now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Brief Introduction
&lt;/h2&gt;

&lt;p&gt;IBM i is an OS that works very well with business applications, reporting, data warehousing, and more. It also comes with a built in database called DB2 which uses its own little flavor of SQL. &lt;/p&gt;

&lt;p&gt;IBM i also has the ability to use many languages such as RPG, CL, DDS, COBOL, BASIC, C/C++, Java, Python, DB2 SQL, and REXX. There is a lot to this machine, but at a high level this amount of information should be sufficient.&lt;/p&gt;

&lt;p&gt;A big selling point of IBM i is its stability. According to developers at my workplace, our IBM i system has only needed to be rebooted once in its 30+ years of operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Brief History
&lt;/h2&gt;

&lt;p&gt;IBM i evolved a lot over time and often gets confusing trying to google things. The easiest way to trace its evolution is to follow the RPG programming language.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1959ish &lt;a href="https://en.wikipedia.org/wiki/IBM_1400_series" rel="noopener noreferrer"&gt;IBM 1400 series&lt;/a&gt; - &lt;strong&gt;RPG I&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Punch cards and magnetic tape&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Also supported COBOL, FORTRAN, and some ancient ASM languages.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;1969-1977 &lt;a href="https://en.wikipedia.org/wiki/IBM_System/3" rel="noopener noreferrer"&gt;IBM System/3&lt;/a&gt; - &lt;strong&gt;RPG II&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Also supported COBOL, FORTRAN, BASIC&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;1978 &lt;a href="https://en.wikipedia.org/wiki/IBM_System/38" rel="noopener noreferrer"&gt;IBM System/38&lt;/a&gt; - &lt;strong&gt;RPG III&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Disk storage, diskette drive, etc.&lt;/li&gt;
&lt;li&gt;Also supported COBOL, BASIC, PL/I&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;1988 &lt;a href="https://en.wikipedia.org/wiki/IBM_System_i" rel="noopener noreferrer"&gt;&lt;strong&gt;Application System/400 - AS/400&lt;/strong&gt;&lt;/a&gt; - &lt;strong&gt;RPG 400/IV&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Also supported ASM, C/C++, COBOL, Python, REXX, and more.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;2000 - renamed to iSeries&lt;/li&gt;

&lt;li&gt;2006 - renamed to System i&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I glossed over a lot of information, but feel free to read more.&lt;/p&gt;

&lt;h2&gt;
  
  
  RPG
&lt;/h2&gt;

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

&lt;p&gt;So, wait...RPG has been around since around &lt;strong&gt;1960&lt;/strong&gt;? &lt;/p&gt;

&lt;p&gt;Yeah. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RPG (Report Program Generator)&lt;/strong&gt; started out on punch cards as a programming language that was used for generating reports. Over its life span, RPG received new features/changes and can currently be used like a general purpose programming language.&lt;/p&gt;

&lt;p&gt;RPG fixed-format looks so ugly because of its origin. Therefore, RPG's grammar is dependent on certain columns needing specific data.&lt;/p&gt;

&lt;p&gt;Gradually, RPG evolved out of its fixed-format ancestry and took a free-format appearance. IBM made sure that there was a decent amount of backwards compatibility between version of RPG. For example, on the AS/400 you could have a mix of RPG III and RPG IV programs. With RPG's evolution into free-format&lt;/p&gt;

&lt;p&gt;RPG is sometimes referred to as RPGLE. Without getting into too much detail: On IBM i, there is the concept of &lt;strong&gt;Integrated Language Environment (ILE)&lt;/strong&gt; languages. ILE languages can talk to other ILE languages. This includes CL, COBOL, C/C++, RPG, and more. Modern RPG development is typically using RPGLE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hello World in fixed-format RPG (RPG III)
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

      C                     MOVEL'HELLO'   HELLO  11
      C                     MOVE 'WORLD'   HELLO
      C           HELLO     DSPLY          WAIT    1
      C                     SETON                     LR


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Hello World in fixed-format RPGLE (RPG IV)
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

      C     'Hello World' DSPLY
      C                   SETON                                        LR


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Hello World in free-format RPGLE (RPG IV)
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

       /free
       dsply ('Hello World');
       *inlr = *on


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

&lt;/div&gt;

&lt;p&gt;With the use of the &lt;strong&gt;/free&lt;/strong&gt; and &lt;strong&gt;/end-free&lt;/strong&gt; you can mix and match fixed and free RPGLE.&lt;/p&gt;

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

&lt;p&gt;This is just a small glimpse at IBM i. There is a mountain of information to learn about the machine, most of which I haven't learned yet. I know this was probably confusing, but I hope my writing was coherent enough to enjoy reading. If anyone would like to read and learn more about IBM i let me know in the comments. I'd love to keep making posts like this.&lt;/p&gt;

&lt;p&gt;Possible future posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is Control Language (CL) ?&lt;/li&gt;
&lt;li&gt;What is Data Description Specification (DDS) ?&lt;/li&gt;
&lt;li&gt;IBM i file structure, Physical Files, and Logical Files&lt;/li&gt;
&lt;li&gt;Calling IBM i from Java, Python, and more&lt;/li&gt;
&lt;li&gt;Writing a basic RPGLE program&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My IBM i "Projects"
&lt;/h2&gt;

&lt;p&gt;To start learning I made a small repository to dump random files and notes into; Located at &lt;a href="https://github.com/barrettotte/IBM-RPG" rel="noopener noreferrer"&gt;https://github.com/barrettotte/IBM-RPG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am writing a small "book" called "Learning IBM i as a Lowly Web Developer" (obviously the title is poking fun). This book will be a casual guide to IBM i , introductions to various obscure languages (RPGLE, CL, DDS, REXX, COBOL, etc), and a short course to wrap-up concepts. &lt;/p&gt;

&lt;p&gt;To go along with my book, I am casually developing an IBM i VS Code extension and editor API to enable viewing, editing, and compiling IBM i code from the comfort of VS Code.&lt;/p&gt;

&lt;p&gt;Thank you for reading.&lt;/p&gt;

</description>
      <category>ibmi</category>
      <category>rpgle</category>
      <category>as400</category>
      <category>rpg</category>
    </item>
  </channel>
</rss>
