<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" >

  <title>Erik L. Arneson — Writer and Software Developer</title>
  <subtitle>Erik L. Arneson is a freelance writer and software developer with WordPress experience. He is located in Portland, Oregon.</subtitle>
  <generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator>
  <link href="https://arnesonium.com/feeds/software-development.xml" rel="self" type="application/atom+xml" />
  <link href="https://arnesonium.com/" rel="alternate" type="text/html" />
  <updated>2026-07-22T04:51:37+00:00</updated>
  <id>https://arnesonium.com/feeds/software-development.xml</id>
  <author>
    <name>Erik L. Arneson</name>
  </author>
      <entry>
        
        <title>How I Learned to Stop Worrying and Love Elementor</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2026/06/wordpress-love-elementor" rel="alternate" type="text/html" title="How I Learned to Stop Worrying and Love Elementor" />
        <updated>2026-06-18T00:00:00+00:00</updated>
        <id>https://arnesonium.com/2026/06/wordpress-love-elementor</id>
          <category term="php" />
        
          <category term="software-development" />
        
          <category term="web-development" />
        
          <category term="wordpress" />
        <content type="html" xml:base="https://arnesonium.com/2026/06/wordpress-love-elementor">&lt;p&gt;I have worked on a quite a few &lt;a href=&quot;/wordpress/&quot;&gt;WordPress projects&lt;/a&gt; lately that use &lt;a href=&quot;https://elementor.com/&quot;&gt;Elementor&lt;/a&gt;, which is a website
builder with a drag-and-drop interface and some other user-friendly bits. In the past, I have
typically avoided these kinds of tools for WordPress, because they caused more problems than they
solved, but recently, my mind has been changed.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;A few months ago, I helped start a new business, &lt;a href=&quot;https://middlechambermedia.com/&quot;&gt;Middle Chamber Media&lt;/a&gt;, which focuses on building websites
for Masonic lodges. My business partner brought me on because of my experience as a &lt;a href=&quot;/software-development/&quot;&gt;web developer&lt;/a&gt;
with &lt;a href=&quot;/wordpress/&quot;&gt;experience with WordPress&lt;/a&gt;. I have built a ton of custom themes in the past, frequently using
either a child theme approach or starting from a bare-bones theme and building from scratch. This
has worked quite well, and though it can produce a robust and speedy website, it can result in
maintenance challenges in the long-run.&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/assets/img/MiddleChamberMedia-Logo-v1.gif&quot; alt=&quot;An animated logo for Middle Chamber Media&quot; /&gt;
  &lt;figcaption&gt;An animated logo that I created for Middle Chamber Media, rendered as an animated GIF.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;However, with Middle Chamber Media, we were suddenly faced with the process of managing and
deploying a large number of WordPress sites, and there are just a couple of us working on it.
Currently, our process involves my partner doing most of the theme development and website setup,
and then I go in and fine-tune the website for responsiveness (i.e. for phones and tablets). This
process has been working pretty well for us.&lt;/p&gt;

&lt;h2 id=&quot;more-elementor-experience&quot;&gt;More Elementor Experience&lt;/h2&gt;

&lt;p&gt;Earlier this year, I also helped another client with an Elementor-based WordPress website. This
client wanted some SEO help, but wanted to continue managing the website on their own. Since the
client is not a WordPress expert, Elementor presented an easy user interface for theme edits. We
worked together, using Elementor to clean things up for SEO purposes. And it worked!&lt;/p&gt;

&lt;p&gt;This processes have led me to a surprising conclusion: &lt;strong&gt;Elementor is great for certain things!&lt;/strong&gt; It has
been a very big time saver and an enabler of collaboration across different WordPress skill levels.
I had to adjust to the new workflow and learn the Elementor editor and paradigm, but it has been
worth it. It is such a huge leap forward compared to previous drag-and-drop theme builders for
WordPress. They all used to really suck!&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Process Automation for an Oregon Charitable Foundation</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2026/05/process-automation-oregon-charitable-foundation" rel="alternate" type="text/html" title="Process Automation for an Oregon Charitable Foundation" />
        <updated>2026-05-22T00:00:00+00:00</updated>
        <id>https://arnesonium.com/2026/05/sref</id>
          <category term="cloud" />
        
          <category term="cloud-computing" />
        
          <category term="golang" />
        
          <category term="svelte" />
        
          <category term="typescript" />
        
          <category term="automation" />
        
          <category term="case-study" />
        
          <category term="google-cloud" />
        
          <category term="programming" />
        
          <category term="testing" />
        
          <category term="web-development" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2026/05/process-automation-oregon-charitable-foundation">&lt;p&gt;The &lt;a href=&quot;https://orsrscholarships.com/&quot;&gt;Oregon Scottish Rite Education Foundation&lt;/a&gt; awards scholarships annually to students across Oregon
who are entering into college or trade schools. Over the past few years, their foundation has grown,
requiring them to distribute more scholarships than ever. However, since the foundation board is
small and composed entirely of volunteers, they were looking for some way to automate their application process to
reduce the number of manual steps required.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;initial-approach&quot;&gt;Initial Approach&lt;/h2&gt;

&lt;p&gt;Members of the board approached me with a wish list of features and requirements. They wanted a
system to integrate seamlessly with their website, while incoming applications should be
automatically checked, sorted, and categorized by county. They already had a spreadsheet system for
tracking applicants as well as a cloud storage system for storing supporting documents; they wanted
the automation system to integrate with these existing components.&lt;/p&gt;

&lt;p&gt;Since the board was already utilizing Google Business products for cloud documents and storage, I
decided that the best approach would be to lean into Google Cloud services. Following their list of
requirements, I implemented a &lt;a href=&quot;https://cloud.google.com/run&quot;&gt;Google Cloud Run&lt;/a&gt; service in &lt;a href=&quot;https://go.dev/&quot;&gt;Go&lt;/a&gt; that processed incoming applications
from their website, then updated the spreadsheet while preparing their cloud storage system for each
application’s supporting documents. The spreadsheet now contained all the application data,
including a link to an automatically generated PDF version of the application and a link to the
cloud storage location.&lt;/p&gt;

&lt;p&gt;This initial approach cut out an enormous amount of manual work. Previously, applications were
submitted via the website and emailed to a board member, who then manually sorted them by county and
generated PDFs for storage and later distribution.&lt;/p&gt;

&lt;h2 id=&quot;implementation-challenges&quot;&gt;Implementation Challenges&lt;/h2&gt;

&lt;p&gt;The application submission window for the Oregon Scottish Rite Education Foundation runs from
December through March of each year, which gave us a limited amount of time to observe incoming live
data and how the automation was performing.&lt;/p&gt;

&lt;p&gt;My initial approach worked fairly well, and handled 94% of incoming applications properly. However,
the last 6% ran into various problems that prevented correct processing. One error arose from a
misspelling in a county name, which was caught early and corrected. Another series of errors arose
from processing errors with the Google Sheets API, which has both rate limiting and more mysterious,
inexplicable errors. I added additional error correction and error checking, but there was still
some additional manual work to enter data from a handful of applications.&lt;/p&gt;

&lt;p&gt;By the end of the application period, we had managed to reduce the amount of manual data entry and
processing by a large percentage, maybe as much as 60%. After discussing the current process
automation with the board, we began to see opportunities for further automation and improvement.&lt;/p&gt;

&lt;h2 id=&quot;additional-development&quot;&gt;Additional Development&lt;/h2&gt;

&lt;p&gt;After the first year’s application submission window, I began working with one of the board members
to plan out how the process could be improved even more. My list of improvements were primarily on
the backend, and involved robuster error detection and reporting, as well as a backup data store
that would allow the automation to recover from the Google Sheets API errors more elegantly.&lt;/p&gt;

&lt;p&gt;The board proposed an additional feature set that would further reduce manual data processing, by
allowing applicants to upload supporting documents such as letters of recommendation and high school
transcripts. These uploaded documents would then be processed and stored in the proper cloud storage
location, thus reducing the amount of manual file management required by volunteers.&lt;/p&gt;

&lt;p&gt;Implementing these two new features went very smoothly. It required the development of a new
frontend, using &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;Typescript&lt;/a&gt; and &lt;a href=&quot;https://svelte.dev/&quot;&gt;Svelte&lt;/a&gt;. This frontend allowed applicants to upload their supporting
documents via a unique link given to each of them by automated email. It used both &lt;a href=&quot;https://cloud.google.com/storage&quot;&gt;Google Cloud
Storage&lt;/a&gt; and the Google Drive API to store these files.&lt;/p&gt;

&lt;p&gt;The improvements on the backend used &lt;a href=&quot;https://cloud.google.com/products/datastore&quot;&gt;Google Cloud Datastore&lt;/a&gt; and a more robust error recovery system.
It now backed up all incoming scholarship applications until they could reliably and more slowly be
added to the spreadsheet with the Google Sheets API, thus nearly eliminating all rate limiting
errors. In addition, progress reports and error output could now be viewed using a new frontend
administrative interface.&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;p&gt;This round of improvements produced significant results. Over the entire span of the second year of
application submissions, error rates dropped from 6% to &lt;em&gt;just one unrecoverable error.&lt;/em&gt; While I had
been hoping for improvement, even I was surprised by how much of an improvement we achieved!&lt;/p&gt;

&lt;p&gt;The board reported that the amount of manual processing was reduced by another 80-90%, with only a
few applicants resorting to email for sending in their supporting documents. While we have discussed
further improvements to the process automation for the next application submission window, the board
is satisfied with the improvements provided by the level of automation implemented so far.&lt;/p&gt;

&lt;h2 id=&quot;lessons&quot;&gt;Lessons&lt;/h2&gt;

&lt;p&gt;This project benefited a lot by reviewing requirements and expectations frequently with the client.
They were great at providing me with very clear goals from the beginning, and as we progressed and
it became clear where the most volunteer time was being spent, we were able to identify more tasks
for automation.&lt;/p&gt;

&lt;p&gt;On the development side of things, three things were clear. First, cloud services really make the
development and deployment of process automation tools like this a breeze. Costs can be kept low
while still providing robust infrastructure for hosting.&lt;/p&gt;

&lt;p&gt;Second, I learned once more the importance of unit tests. I wrote unit tests for most elements of
the automation software, which allowed me to catch breaking changes and test features very quickly.
&lt;a href=&quot;https://www.ibm.com/think/topics/test-driven-development&quot;&gt;Test-driven development&lt;/a&gt; can be a great way to run a project, and though I did not follow all of its
parameters strictly, that particular philosophy did guide my decision.&lt;/p&gt;

&lt;p&gt;Third, once more I was reminded of how the best-planned software runs into difficulties when it
collides with the real world. I failed to anticipate the Google Sheets API issues and did not
implement enough comprehensive error correction early on. That is not an error I shall repeat again!&lt;/p&gt;

&lt;p&gt;Finally, I learned that even with a project that seems as straightforward as this one, it is
important to control expectations early. This turned into a multiyear project because we saw room
for improvement. I think it is important for a business or organization looking for process
automation to understand that it can be an ongoing series of improvements; not everything will be
accomplished or perfected after one pass.&lt;/p&gt;

&lt;p&gt;Overall, I found this to be a rewarding project. I enjoyed working on software that was aiding a
good cause: helping high school graduates fund their education. It was also very nice to work for a
charitable foundation instead of a for-profit business; it made all of my programming feel a lot
better. I hope to work for more charitable foundations in the future.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Configuring Emacs 29.1 for Go Development</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2023/08/configuring-emacs-29-1-for-golang" rel="alternate" type="text/html" title="Configuring Emacs 29.1 for Go Development" />
        <updated>2023-08-01T00:00:00+00:00</updated>
        <id>https://arnesonium.com/2023/08/golang-emacs</id>
          <category term="emacs" />
        
          <category term="programming" />
        
          <category term="golang" />
        
          <category term="lisp" />
        
          <category term="emacs-lisp" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2023/08/configuring-emacs-29-1-for-golang">&lt;p&gt;Now that I have &lt;a href=&quot;https://arnesonium.com/2023/07/emacs-29-1-on-ubuntu-22-04-lts&quot;&gt;installed Emacs 29.1&lt;/a&gt;, I needed to get it set up for Go development for a project. I was interested in taking advantage of both the new Tree-Sitter integration, and the new Eglot language server client. However, they were mildly tricky to set up! Here is what I did.
&lt;!--more--&gt;&lt;/p&gt;

&lt;h2 id=&quot;configuring-tree-sitter-for-go&quot;&gt;Configuring Tree-Sitter for Go&lt;/h2&gt;

&lt;p&gt;If you follow the excellent &lt;a href=&quot;https://www.masteringemacs.org/article/how-to-get-started-tree-sitter&quot;&gt;How to Get Started with Tree-Sitter&lt;/a&gt; instructions from Mickey Peterson, you will have a great head-start on getting Tree-Sitter working for most of your favorite languages (and probably Java, too). However, those instructions didn’t cover everything I needed for Go. When I tried running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M-x go-ts-mode&lt;/code&gt;, Emacs complained about a missing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gomod&lt;/code&gt; module. Baffling!&lt;/p&gt;

&lt;p&gt;I couldn’t find any information in the Emacs documentation about where to find this missing module. I looked around on the net and found &lt;a href=&quot;https://github.com/camdencheek/tree-sitter-go-mod&quot;&gt;Camden Cheek’s tree-sitter-go-mod&lt;/a&gt;, and added that to my list of recipes. My &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;treesit-language-source-alist&lt;/code&gt; then looked like this:&lt;/p&gt;

&lt;div class=&quot;language-elisp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;setq&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;treesit-language-source-alist&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bash&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-bash&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cmake&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/uyha/tree-sitter-cmake&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;css&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-css&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;elisp&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/Wilfred/tree-sitter-elisp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-go&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gomod&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/camdencheek/tree-sitter-go-mod&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dockerfile&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/camdencheek/tree-sitter-dockerfile&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;javascript&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-javascript&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;master&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/alemuller/tree-sitter-make&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;markdown&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/ikatyang/tree-sitter-markdown&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;python&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-python&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;toml&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-toml&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tsx&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-typescript&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;master&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;tsx/src&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;typescript&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/tree-sitter/tree-sitter-typescript&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;master&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;typescript/src&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;yaml&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://github.com/ikatyang/tree-sitter-yaml&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the package is named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go-mod&lt;/code&gt; but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go-ts-mode&lt;/code&gt; expects it to be named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gomod&lt;/code&gt;. I wish this were documented somewhere! In any case, I was then able to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M-x treesit-install-language-grammar&lt;/code&gt; for both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gomod&lt;/code&gt;. Finally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M-x go-ts-mode&lt;/code&gt; worked!&lt;/p&gt;

&lt;p&gt;After going through this process, I found &lt;a href=&quot;https://robbmann.io/posts/emacs-treesit-auto/&quot;&gt;Robert Enzmann’s post about automatically using Tree-Sitter&lt;/a&gt;. He has created the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;treesit-auto&lt;/code&gt; package, now available on MELPA, that does most of this work for you. It is a much faster way of solving the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gomod&lt;/code&gt; mystery, so give it a shot!&lt;/p&gt;

&lt;h2 id=&quot;configuring-eglot-for-go&quot;&gt;Configuring Eglot for Go&lt;/h2&gt;

&lt;p&gt;I’d been using &lt;a href=&quot;https://github.com/emacs-lsp/lsp-mode&quot;&gt;lsp-mode&lt;/a&gt; for ages, but with Emacs 29.1 including &lt;a href=&quot;https://joaotavora.github.io/eglot/&quot;&gt;Eglot&lt;/a&gt;, I decided to make the switch.&lt;/p&gt;

&lt;p&gt;In my Go project, I ran &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M-x eglot&lt;/code&gt; and was immediately met with an error:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[eglot] Server reports (type=1): Error loading workspace folders (expected 1, got 0)
failed to load view for file:///path/to/my/project: err: go command required, not found: exec: &quot;go&quot;: executable file not found in $PATH: stderr: 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve got Go installed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/go&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/go/bin&lt;/code&gt; is definitely in my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exec-path&lt;/code&gt; variable in Emacs. It looked like Eglot wasn’t propagating &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exec-path&lt;/code&gt; down to its subprocesses. How annoying! I did a quick search through the list of Eglot-related variables and the Eglot documentation and no solution seemed immediately forthcoming.&lt;/p&gt;

&lt;p&gt;So I took the cheap way out and made a symlink. In my shell, I ran:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-sf&lt;/span&gt; /usr/local/go/bin/go /usr/local/bin/go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is a dumb trick, and I am sure there is a better way to solve it. Do you know of one? Please comment and let me know!&lt;/p&gt;

&lt;h2 id=&quot;what-else&quot;&gt;What Else?&lt;/h2&gt;

&lt;p&gt;My exploration has revealed that there’s a lot of work left to do in the Emacs Tree-Sitter world. There are plenty of languages major modes that don’t yet have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ts-mode&lt;/code&gt; equivalent, and plenty of others that still need a lot of work.&lt;/p&gt;

&lt;p&gt;It’s too soon for me to say if this setup is preferrable to my previous configuration. But I am really looking forward to playing around with Eglot’s features and exploring the capabilities of Tree-Sitter.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Pattern Matching and Tail Recursion in Emacs Lisp</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2022/11/pattern-matching-tail-recursion-emacs-lisp" rel="alternate" type="text/html" title="Pattern Matching and Tail Recursion in Emacs Lisp" />
        <updated>2022-11-19T00:00:00+00:00</updated>
        <id>https://arnesonium.com/2022/11/tco-pattern-emacs-lisp</id>
          <category term="emacs" />
        
          <category term="programming" />
        
          <category term="emacs-lisp" />
        
          <category term="lisp" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2022/11/pattern-matching-tail-recursion-emacs-lisp">&lt;p&gt;Functional programming offers a bunch of really cool programming patterns. Two that I really enjoy are &lt;a href=&quot;https://stackoverflow.com/questions/310974/what-is-tail-call-optimization&quot;&gt;tail recursion&lt;/a&gt; and &lt;a href=&quot;https://sodocumentation.net/ocaml/topic/2656/pattern-matching&quot;&gt;pattern matching&lt;/a&gt;, especially how they are implemented in OCaml. However, I spend a lot of time writing Emacs Lisp now, and I was wondering if I could find a way to use these patterns in that language.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;It turns out that it is possible, thanks to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;named-let&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcase&lt;/code&gt;. It isn’t as pretty and elegant as OCaml, but at least I get to keep excercising those parts of my programming brain. Maybe next I’ll try to figure out currying in Emacs Lisp.&lt;/p&gt;

&lt;p&gt;Note that this blog post includes some &lt;em&gt;really dumb&lt;/em&gt; examples, because that’s usually how I learn these things best.&lt;/p&gt;

&lt;h2 id=&quot;pattern-matching-with-pcase&quot;&gt;Pattern Matching with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcase&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Most programmers will be familiar with the granddaddy of pattern matching, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch/case&lt;/code&gt; construct. This is present in many, many programming languages, especially those in the ALGOL family.&lt;/p&gt;

&lt;p&gt;However, pattern matching can be so much more! Instead of simple equality checks, pattern matching extends the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch/case&lt;/code&gt; concept to include testing for all kinds of patterns and conditionals.&lt;/p&gt;

&lt;p&gt;Lisp programmers will already be familiar with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cond&lt;/code&gt;, which can be used to sequentially test for conditionals. However, functional language programmers have probably fallen in love with a more mature and sophisticated form of pattern matching that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cond&lt;/code&gt; doesn’t totally satisfy.&lt;/p&gt;

&lt;p&gt;Fortunately, Emacs Lisp has &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/elisp/Pattern_002dMatching-Conditional.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcase&lt;/code&gt;, the pattern-matching conditional&lt;/a&gt;. Here is an example of its use to duplicate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;car&lt;/code&gt;, which is the dumbest possible example I could think of.&lt;/p&gt;

&lt;div class=&quot;language-elisp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ela/car&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pcase&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;lst&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;nv&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;
     &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can see that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcase&lt;/code&gt; has a backquote syntax for matching various constructs, such as with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;`(,head . ,_)&lt;/code&gt; piece. This matches a cons cell and binds the CAR to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;head&lt;/code&gt; while ignoring the CDR.&lt;/p&gt;

&lt;p&gt;The next case is just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt;, which is a catch-all matching operator.&lt;/p&gt;

&lt;p&gt;In the real world, you’d probably want some type checking and error correction, but I promised very simple examples. Check out the full range of &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/elisp/pcase-Macro.html&quot;&gt;matching capabilities for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcase&lt;/code&gt;&lt;/a&gt;, and then &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote-Patterns.html&quot;&gt;read about all of the backquote patterns you can also use&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;tail-call-optimization-with-named-let&quot;&gt;Tail Call Optimization with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;named-let&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Tail call optimization (TCO) is the programming language feature that allows efficient tail recursion without overflowing your stack. It is increasingly common in languages today, though from what I’ve seen, it always involves caveats.&lt;/p&gt;

&lt;p&gt;In Emacs Lisp, the easiest way to use TCO that I’ve come across is the &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/elisp/Local-Variables.html#index-named_002dlet&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;named-let&lt;/code&gt; macro&lt;/a&gt;. With it, you define a function that can get “unrolled” inside another function. For example, here is a simple function that calculates a factorial using tail recursion.&lt;/p&gt;

&lt;div class=&quot;language-elisp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ela/fact&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;in-num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;named-let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rec-fact&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;accu&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;in-num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pcase&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;num&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rec-fact&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;accu&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;
       &lt;span class=&quot;nv&quot;&gt;accu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, you will notice that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rec-fact&lt;/code&gt; is the locally named function that gets called at the end of the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcase&lt;/code&gt; pattern. This is a tail call! It will get optimized.&lt;/p&gt;

&lt;p&gt;You can check this out by running something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(ela/fact 5)&lt;/code&gt; and getting 120 as the result. Try using a ridiculously big number and see if you get a stack overflow! You shouldn’t.&lt;/p&gt;

&lt;h2 id=&quot;another-example-summing-a-list&quot;&gt;Another Example: Summing a List&lt;/h2&gt;

&lt;p&gt;This is just a nostalgic example, since it’s probably the first tail recursive pattern matching function I ever wrote when learning OCaml a zillion years ago. This function will take a list of numbers and then add them all together. There are much better ways to write this in Emacs Lisp, like with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-elisp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ela/sum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;named-let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;sum-list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;accu&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pcase&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;lst&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sum-list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;accu&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;
       &lt;span class=&quot;nv&quot;&gt;accu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can then call it like this:&lt;/p&gt;

&lt;div class=&quot;language-elisp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ela/sum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And you will end up with exactly the result you expect. I was amused to see that the documentation page for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;named-let&lt;/code&gt; has a different implementation of this function that doesn’t use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcase&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Oh heck, let’s get fancy and rewrite &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt; using this approach.&lt;/p&gt;

&lt;div class=&quot;language-elisp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ela/apply&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;&amp;amp;rest&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;Apply FN to each element of ARGUMENTS and return the accumulated result.&quot;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;;; Set up accumulator to the right type.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;arguments-flat&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;flatten-list&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;initial-value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pcase&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;car&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arguments-flat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pred&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;integerp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pred&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;stringp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;named-let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;apply-rec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;accumulator&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;initial-value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input-list&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;arguments-flat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pcase&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;input-list&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;apply-rec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;funcall&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;accumulator&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;
         &lt;span class=&quot;nv&quot;&gt;accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I am certain this version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply&lt;/code&gt; has bugs, but it works for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;concat&lt;/code&gt;, so that’s good enough for a simple example. And it uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pcase&lt;/code&gt; twice!&lt;/p&gt;

&lt;p&gt;Hopefully this has been a useful blog post for somebody out there. Let me know in the comments if there are other fun things you have done with TCO and pattern matching in Emacs Lisp!&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>New MELPA Package: ddate</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2022/11/new-melpa-package-ddate" rel="alternate" type="text/html" title="New MELPA Package: ddate" />
        <updated>2022-11-01T00:00:00+00:00</updated>
        <id>https://arnesonium.com/2022/11/ddate-on-melpa</id>
          <category term="emacs" />
        
          <category term="discordian" />
        
          <category term="melpa" />
        
          <category term="lisp" />
        
          <category term="programming" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2022/11/new-melpa-package-ddate">&lt;p&gt;I recently wrote an Emacs Lisp package to support the &lt;a href=&quot;https://github.com/bo0ts/ddate&quot;&gt;ddate&lt;/a&gt; command, a classic
command-line utility to display dates from the &lt;a href=&quot;https://en.wikipedia.org/wiki/Discordian_calendar&quot;&gt;Discordian calendar&lt;/a&gt;.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;The package is now &lt;a href=&quot;https://melpa.org/#/ddate&quot;&gt;available on MELPA&lt;/a&gt;! That means that if you have &lt;a href=&quot;https://ianyepan.github.io/posts/setting-up-use-package/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;use-package&lt;/code&gt;
installed&lt;/a&gt;, you can get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ddate&lt;/code&gt; easily like this:&lt;/p&gt;

&lt;div class=&quot;language-emacs-lisp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;use-package&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ddate&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ensure&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once you have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ddate&lt;/code&gt; package installed, you can use it to add the Discordian date to your &lt;a href=&quot;https://github.com/emacs-dashboard/emacs-dashboard&quot;&gt;dashboard&lt;/a&gt; with code like
this:&lt;/p&gt;

&lt;div class=&quot;language-emacs-lisp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ela/dashboard-insert-ddate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;list-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;Insert the Discordian date into the dashboard.&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ddate-string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ddate-pretty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dashboard-center-line&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ddate-string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ddate-string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;use-package&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dashboard&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:init&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dashboard-setup-startup-hook&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:config&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;;; Add the ddate item provider to the list.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;add-to-list&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&apos;dashboard-item-generators&lt;/span&gt;
               &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ddate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ela/dashboard-insert-ddate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;;; Set up your items with ddate at the top.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;setq&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;dashboard-items&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ddate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;recents&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;bookmarks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can view the &lt;a href=&quot;https://git.sr.ht/~earneson/emacs-ddate&quot;&gt;source code for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ddate&lt;/code&gt; on Sourcehut&lt;/a&gt;.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Arduino Planetary Hours library</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2017/05/arduino-planetary-hours-library/" rel="alternate" type="text/html" title="Arduino Planetary Hours library" />
        <updated>2017-05-01T18:30:35+00:00</updated>
        <id>https://arnesonium.com/2017/05/arduino-planetary-hours-library</id>
          <category term="arduino" />
        
          <category term="c" />
        
          <category term="planetary-hours" />
        
          <category term="programming" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2017/05/arduino-planetary-hours-library/">&lt;p&gt;I am finally announcing my &lt;a href=&quot;https://bitbucket.org/arnesonium/planetaryhours&quot;&gt;PlanetaryHours library for the Arduino&lt;/a&gt;. This library uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sun_rise()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sun_set()&lt;/code&gt; functions from the &lt;a href=&quot;http://www.nongnu.org/avr-libc/user-manual/group__avr__time.html&quot;&gt;avr-libc time.h&lt;/a&gt; library to calculate planetary hours.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;button&quot; href=&quot;https://bitbucket.org/arnesonium/planetaryhours/get/v1.0.zip&quot;&gt;Download v1.0 Here&lt;/a&gt;
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;Planetary hours are an old method of figuring out which planets are “in charge” at any moment. For more information on planetary hours, check out these resources:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.renaissanceastrology.com/planetaryhoursarticle.html&quot; target=&quot;_blank&quot;&gt;http://www.renaissanceastrology.com/planetaryhoursarticle.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.esotericarchives.com/agrippa/agripp2c.htm#chap34&quot; target=&quot;_blank&quot;&gt;http://www.esotericarchives.com/agrippa/agripp2c.htm#chap34&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can set up a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PlanetaryHour&lt;/code&gt; object by passing it a time zone offset in hours, a latitude, and a longitude. The following example might help.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#define MYZONE -7
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PlanetaryHour&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ph&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MYZONE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;45.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;122.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, you can check the ruling planet of the current day and hour with an RTC or other time-keeping mechanism.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;time_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unixtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UNIX_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dayPlanet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ph&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dayPlanet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hourPlanet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ph&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hourPlanet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The return value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dayPlanet()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hourPlanet()&lt;/code&gt; is a number from 0 to 6, corresponding to the Chaldean planetary order.&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#define SATURN 0
#define JUPITER 1
#define MARS 2
#define SUN 3
#define VENUS 4
#define MERCURY 5
#define MOON 6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ll be posting an article on &lt;a href=&quot;http://www.arnemancy.com/&quot; target=&quot;_blank&quot;&gt;the Arnemancy blog&lt;/a&gt; outlining a project I just installed using this library and some &lt;a href=&quot;https://www.adafruit.com/category/168&quot; target=&quot;_blank&quot;&gt;NeoPixels&lt;/a&gt;. I really look forward to seeing what others end up doing with this code!&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;button&quot; href=&quot;https://bitbucket.org/arnesonium/planetaryhours/get/v1.0.zip&quot;&gt;Download v1.0 Here&lt;/a&gt;&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Raspberry Pi GPIO with Erlang</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2017/04/raspberry-pi-gpio-with-erlang/" rel="alternate" type="text/html" title="Raspberry Pi GPIO with Erlang" />
        <updated>2017-04-10T17:23:14+00:00</updated>
        <id>https://arnesonium.com/2017/04/raspberry-pi-gpio-with-erlang</id>
          <category term="erlang" />
        
          <category term="programming" />
        
          <category term="raspberry-pi" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2017/04/raspberry-pi-gpio-with-erlang/">&lt;p&gt;Raspberry Pis are super cool. One of the neat things about them is that they have a ton of general purpose input/output (GPIO) pins, so you can use them to control all sorts of external devices. Unfortunately, most of the examples and applications are written in Python. I know, a lot of people really love Python, but it’s just not my cup of tea.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;Enter the &lt;a href=&quot;https://github.com/paoloo/gpio&quot; target=&quot;_blank&quot;&gt;Erlang πGPIO library&lt;/a&gt; by &lt;a href=&quot;https://paoloo.github.io/&quot; target=&quot;_blank&quot;&gt;Paolo Oliveira&lt;/a&gt;! This is a simple, straightforward library that implements the RPi GPIO stuff for Erlang. Using it, I have created an Erlang library to control a 28BYJ-48 5V stepper motor with a ULN2003 controller board.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;button&quot; href=&quot;https://github.com/pymander/stepper&quot; target=&quot;_blank&quot;&gt;Check out the library here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;https://www.instagram.com/p/BSp2ZdSA0cg/?taken-by=pymander&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Using Amazon S3 as a Nette Service</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2016/10/using-amazon-s3-as-a-nette-service/" rel="alternate" type="text/html" title="Using Amazon S3 as a Nette Service" />
        <updated>2016-10-26T22:17:16+00:00</updated>
        <id>https://arnesonium.com/2016/10/using-amazon-s3-as-a-nette-service</id>
          <category term="aws" />
        
          <category term="nette" />
        
          <category term="php" />
        
          <category term="programming" />
        
          <category term="s3" />
        
          <category term="web-development" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2016/10/using-amazon-s3-as-a-nette-service/">&lt;p&gt;&lt;a href=&quot;https://nette.org/&quot;&gt;Nette&lt;/a&gt; is a popular web application framework for PHP. It is mostly pretty well documented and easy to use. Recently, I needed to upload media from a Nette application to &lt;a href=&quot;https://aws.amazon.com/s3/&quot;&gt;Amazon S3&lt;/a&gt;. This is how I created an S3 service for my Nette application. You will need to be familiar with Nette and have an existing Nette application to follow along.
&lt;!--more--&gt;&lt;/p&gt;

&lt;h1 id=&quot;installing-the-amazon-web-services-sdk&quot;&gt;Installing the Amazon Web Services SDK&lt;/h1&gt;

&lt;p&gt;Before anything will work, you will need to install the AWS SDK using Composer. Run the following command from your Nette project directory.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;php composer.phar require aws/aws-sdk-php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;the-s3uploader-service&quot;&gt;The S3Uploader Service&lt;/h1&gt;

&lt;p&gt;Next, create the file &lt;strong&gt;app/model/S3Uploader.php&lt;/strong&gt; and edit it to look like the following. You can also download my version &lt;a href=&quot;https://gist.github.com/pymander/a027523a7b9152660fac8e7bb4801c91&quot;&gt;from this link&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;App\Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Nette&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Aws\S3\S3Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;S3Uploader&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/** @var \Aws\S3\S3Client */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$s3client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/** @var string */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$accessKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$secretKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;putenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AWS_ACCESS_KEY_ID=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$accessKey&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;putenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AWS_SECRET_ACCESS_KEY=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$secretKey&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;\Aws\S3\S3Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;version&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;latest&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;region&apos;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;us-west-2&apos;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * Upload a file to an S3 bucket
     *
     * @param string $key The key used for the uploaded object
     * @param string $file The filename to be uploaded
     * @param string $contentType The file&apos;s content type. This defaults to &quot;application/octet-stream&quot;
     *
     * @return string A URL to access the file publically.
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uploadPublic&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$contentType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;application/octet-stream&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;putObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;Bucket&apos;&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;Key&apos;&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;SourceFile&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;ContentType&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;ACL&apos;&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;public-read&apos;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getObjectUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getClient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getBucket&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;configuring-the-configurator&quot;&gt;Configuring the Configurator&lt;/h1&gt;

&lt;p&gt;Finally, the tricky part. You need to configure the &lt;a href=&quot;https://doc.nette.org/en/2.4/configuring&quot;&gt;Nette Configurator&lt;/a&gt; so it knows about your new service. Follow these directions.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Open &lt;strong&gt;app/config/config.neon&lt;/strong&gt; with your favorite text editor. At the end of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;services:&lt;/code&gt; section, add the following line.&lt;/p&gt;

    &lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;App&lt;/span&gt;\&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;\&lt;span class=&quot;n&quot;&gt;S3Uploader&lt;/span&gt;(%&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;%, %&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;access_key&lt;/span&gt;%, %&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;.&lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;%)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Open &lt;strong&gt;app/config/config.local.neon&lt;/strong&gt;. Find the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parameters:&lt;/code&gt; section and add this block to it. Replace “ACCESS_KEY” with your AWS access key, and “SECRET_KEY” with your AWS secret key. Set “BUCKET_NAME” to the bucket you’ll be using for your uploads.&lt;/p&gt;

    &lt;div class=&quot;language-conf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;s3client&lt;/span&gt;:
   &lt;span class=&quot;n&quot;&gt;access_key&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;ACCESS_KEY&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;secret_key&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;SECRET_KEY&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;BUCKET_NAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;using-s3uploader&quot;&gt;Using S3Uploader&lt;/h1&gt;

&lt;p&gt;Open up the presenter file that will be using the S3Uploader service. You just need to add a few new lines.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Near the top of the file where you’re loading libraries, add this line.&lt;/p&gt;

    &lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;App\Model\S3Uploader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You will need to change your constructor definition to include S3Uploader. Assuming you haven’t changed your constructor function too much, it will probably look like the following.&lt;/p&gt;

    &lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Nette&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;\Database\Context&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$database&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;S3Uploader&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Finally, you can call the S3Uploader with a simple method call.&lt;/p&gt;

    &lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$objectUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$s3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;uploadPublic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$objectKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$filePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Good luck with S3Uploader. Please let me know in the comments how it is working for you. Note that this is an example and the finished product will probably be more sophisticated. However, this should get you started with using Amazon S3 in your Nette applications.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>CenturyLink AppFog Tutorial</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2016/01/centurylink-appfog-tutorial/" rel="alternate" type="text/html" title="CenturyLink AppFog Tutorial" />
        <updated>2016-01-15T17:26:41+00:00</updated>
        <id>https://arnesonium.com/2016/01/centurylink-appfog-tutorial</id>
          <category term="appfog" />
        
          <category term="centurylink-cloud" />
        
          <category term="cloud-computing" />
        
          <category term="cloudfoundry" />
        
          <category term="javascript" />
        
          <category term="node-js" />
        
          <category term="programming" />
        
          <category term="web-development" />
        
          <category term="writing" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2016/01/centurylink-appfog-tutorial/">&lt;p&gt;Recently I wrote a tutorial with &lt;a href=&quot;http://wordlions.com/&quot; target=&quot;_blank&quot;&gt;Word Lions&lt;/a&gt; for &lt;a href=&quot;http://ctl.io/&quot; target=&quot;_blank&quot;&gt;CenturyLink Cloud&lt;/a&gt; that teaches how to build and deploy a Node.js application to CenturyLink AppFog. The tutorial and application were really fun to build and write. It was my first Node.js project, and my first experience with CloudFoundry. The tutorial uses the following CenturyLink Cloud products:
&lt;!--more--&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.ctl.io/appfog/&quot;&gt;AppFog&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.ctl.io/orchestrate/&quot;&gt;Orchestrate&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.ctl.io/object-storage/&quot;&gt;Object Storage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AppFog is CenturyLink Cloud’s CloudFoundry system. It is really powerful, and it appears to be more flexible than &lt;a href=&quot;https://arnesonium.com/tag/google-cloud/&quot;&gt;Google App Engine&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Read the Tutorial&lt;/h2&gt;

&lt;p&gt;The tutorial walks you through building a document storage system with a built-in PDF reader and comment storage. It also includes user authentication and some other neat Node.js tricks. You can follow the tutorial from the following links, which will include all of the information needed to get you up and running on AppFog with Node.js. Enjoy!&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.ctl.io/developers/blog/post/deploy-app-user-login&quot;&gt;Deploy an App With User Login&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.ctl.io/developers/blog/post/appfog-object-storage&quot;&gt;Using CenturyLink Cloud for Object Storage&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.ctl.io/developers/blog/post/search-document-metadata&quot;&gt;Add Search Capabilities with Orchestrate&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://www.ctl.io/developers/blog/post/document-review-comment&quot;&gt;Building a PDF Viewer and Comment System&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content>
      </entry>
    
      <entry>
        
        <title>Please Use Version Control</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2015/04/please-use-version-control/" rel="alternate" type="text/html" title="Please Use Version Control" />
        <updated>2015-04-09T03:07:44+00:00</updated>
        <id>https://arnesonium.com/2015/04/please-use-version-control</id>
          <category term="git" />
        
          <category term="github" />
        
          <category term="programming" />
        
          <category term="stack-overflow" />
        
          <category term="version-control" />
        
          <category term="web-development" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2015/04/please-use-version-control/">&lt;p&gt;Stack Overflow released their &lt;a href=&quot;http://stackoverflow.com/research/developer-survey-2015&quot; title=&quot;Stack Overflow Developer Survey 2015&quot; target=&quot;_blank&quot;&gt;2015 Developer Survey&lt;/a&gt; this week, and it has some interesting results. There are plenty of articles being written about their findings, so I’m only going to focus on one of them: version control.
&lt;!--more--&gt;&lt;/p&gt;

&lt;h2&gt;9.3% of Respondents Don&apos;t Use Version Control&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://arnesonium.com/wp-content/uploads/2015/04/Screenshot-from-2015-04-08-192457.png&quot; alt=&quot;Almost 10% of programmers aren&apos;t using version control.&quot; width=&quot;300&quot; height=&quot;188&quot; class=&quot;size-medium wp-image-345&quot; /&gt;&lt;/p&gt;

&lt;p&gt;StackOverflow says that &lt;a href=&quot;http://stackoverflow.com/research/developer-survey-2015#tech-sourcecontrol&quot; title=&quot;Stack Overflow Developer Survey 2015&quot; target=&quot;_blank&quot;&gt;almost 10% of developers still aren’t using version control&lt;/a&gt;. This is terrible. If you happen to be one of the developers who hasn’t adopted version control yet, &lt;b&gt;make it your next priority!&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Version control, also known as source control or revision control, is vital to best programming practices. It provides an incremental backup along with comments and notes on changes that have been made. It provides a view of changes and all kinds of handy features, such as handling conflicts between changes, release tagging, code branches, and more. If you aren’t sure what version control is, check out Ilya Olevsky’s post, &lt;a href=&quot;http://www.codeservedcold.com/version-control-importance/&quot; title=&quot;Why Version Control is Critical to Your Success&quot; target=&quot;_blank&quot;&gt;“Why Version Control is Critical to Your Success,”&lt;/a&gt; and then come back here.&lt;/p&gt;

&lt;h2&gt;Essential to Collaboration and Continuity&lt;/h2&gt;

&lt;p&gt;If you are looking to hire a freelance developer, make sure you hire one that uses version control. It is essential to maintaining a healthy history of code releases, project updates, and bug fixes. What if you only need to use your freelancer every once in a while? What if you decide to add more developers, or change developers all together? Without version control, this becomes a nightmare.&lt;/p&gt;

&lt;p&gt;A client recently brought me a project that had been built by another developer a couple of years ago. They wanted to move their web application from one host to another. However, there was a lot that needed to be cleaned up before the move could happen, including some outdated PHP code and odd database settings. In the project’s main directory, there was a mess of old, unused source code files. Just the &lt;code&gt;index.php&lt;/code&gt; file had multiple versions:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;index2.php&lt;/li&gt;
	&lt;li&gt;index3.php&lt;/li&gt;
	&lt;li&gt;indexold.php&lt;/li&gt;
	&lt;li&gt;index.php_old&lt;/li&gt;
	&lt;li&gt;index.php_bak&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all, there were 598 unused files that were unnecessary backups of old, broken code. This type of mess is easily avoided with version control. Please stay sane, keep your customers happy, and your source code easy to navigate. Use version control.&lt;/p&gt;

&lt;h2&gt;Getting Started with Version Control&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://arnesonium.com/wp-content/uploads/2015/04/git-logo.png&quot; alt=&quot;git-logo&quot; width=&quot;220&quot; height=&quot;92&quot; class=&quot;alignright size-full wp-image-347&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you’ve decided to make the right move and start using version control, you will see that there are many to choose from. However, if you’re just going to learn one, you should start with &lt;b&gt;Git&lt;/b&gt;. As you can see from the survey, it is the most widely used. The best place to start is probably in the free e-book offered by the Git development team. &lt;a href=&quot;http://git-scm.com/book/en/v1/Getting-Started&quot; title=&quot;Git: Getting Started&quot; target=&quot;_blank&quot;&gt;Click here to get started.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;If You&apos;re Doing It, Thank You&lt;/h2&gt;

&lt;p&gt;The first time I encountered a team that wasn’t using version control, I was shocked. The second time, I sighed in exasperation. Now, I am thankful that over 90% of developers are using it, and I look forward to the day that every project I join comes with a &lt;code&gt;git log&lt;/code&gt; command. If you are using version control, I hope you spread the word and make sure that your fellow programmers are doing it, too. Save the rest of us some pain!&lt;/p&gt;

&lt;p&gt;As a bonus, here’s my favorite &lt;code&gt;git log&lt;/code&gt; command. Add it to your aliases.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--graph&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--all&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--decorate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;The featured image for this post is a pile of logs, to remind you that logs are important, and a vital part of version control.&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Create a Document From Twitter with TweetBook</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2015/04/create-a-document-from-twitter-with-tweetbook/" rel="alternate" type="text/html" title="Create a Document From Twitter with TweetBook" />
        <updated>2015-04-01T17:48:56+00:00</updated>
        <id>https://arnesonium.com/2015/04/create-a-document-from-twitter-with-tweetbook</id>
          <category term="golang" />
        
          <category term="google-cloud" />
        
          <category term="programming" />
        
          <category term="publishing" />
        
          <category term="tweetbook" />
        
          <category term="twitter" />
        
          <category term="web-development" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2015/04/create-a-document-from-twitter-with-tweetbook/">&lt;p&gt;I just released &lt;a href=&quot;http://tweetbook.arnesonium.com/&quot; title=&quot;TweetBook&quot; target=&quot;_blank&quot;&gt;TweetBook&lt;/a&gt;, a web application to transform a Twitter stream into a simple document that can easily be turned into a photo album.
&lt;!--more--&gt;&lt;/p&gt;

&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;A client came to me complaining that there was no available solution to export a Twitter feed as a document filled with images. There are various other Twitter-to-document converters out there, but they all focus on the text. The client asked me to build a tool to fill this void.&lt;/p&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;Since I’ve been working with Google App Engine a lot lately, I used Go to write a tool that retrieves Tweets from a search or timeline. It provides a number of formatting options, and then creates a simple document suitable for exporting into an HTML or PDF file.&lt;/p&gt;

&lt;h2&gt;Try It Out!&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;As of 2022, this application is seven years old and probably doesn’t work anymore.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The client told me to do whatever I wanted with the code, so I’m making it available for use! &lt;strong&gt;&lt;a href=&quot;http://tweetbook.arnesonium.com/&quot; title=&quot;TweetBook&quot; target=&quot;_blank&quot;&gt;Click here to try TweetBook!&lt;/a&gt;&lt;/strong&gt; If you find it useful, please consider funding further development by contributing a small amount with this button:&lt;/p&gt;

&lt;form action=&quot;https://www.paypal.com/cgi-bin/webscr&quot; method=&quot;post&quot; target=&quot;_top&quot;&gt;
 &lt;button type=&quot;submit&quot; class=&quot;btn&quot;&gt;Contribute $1.99 &amp;raquo;&lt;/button&gt;&lt;input type=&quot;hidden&quot; name=&quot;cmd&quot; value=&quot;_s-xclick&quot; /&gt;&lt;input type=&quot;hidden&quot; name=&quot;hosted_button_id&quot; value=&quot;3PNSJJHRF9XWA&quot; /&gt;
 &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;https://www.paypalobjects.com/en_US/i/scr/pixel.gif&quot; width=&quot;1&quot; height=&quot;1&quot; /&gt;
&lt;/form&gt;

&lt;h2&gt;Do You Have a Suggestion? A Bug Report?&lt;/h2&gt;
&lt;p&gt;If you have additional ideas for TweetBook, please visit my &lt;a href=&quot;http://arnesonium.com/contact/&quot; title=&quot;Contact&quot;&gt;Contact page&lt;/a&gt;. I’m eager to hear your feedback and get suggestions and bug reports!&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Pansophie Online Color Test</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2015/02/pansophie-online-color-test/" rel="alternate" type="text/html" title="Pansophie Online Color Test" />
        <updated>2015-02-23T16:46:52+00:00</updated>
        <id>https://arnesonium.com/2015/02/pansophie-online-color-test</id>
          <category term="javascript" />
        
          <category term="jquery" />
        
          <category term="php" />
        
          <category term="programming" />
        
          <category term="web-design" />
        
          <category term="web-development" />
        
          <category term="zend-framework" />
        
          <category term="software-development" />
        
          <category term="case-study" />
        <content type="html" xml:base="https://arnesonium.com/2015/02/pansophie-online-color-test/">&lt;p&gt;&lt;a href=&quot;http://eyesandedge.com/pansophie/&quot; target=&quot;_blank&quot;&gt;Pansophie Personality and Color&lt;/a&gt; is focused on mapping personalities to colors. Alexandra Hall wanted an online testing platform with flexible questions, testing mechanisms, and report generation. I built a full-featured web application to meet Pansophie PC’s requirements. This was one of my early Zend Framework projects, but it ended up with some neat features.
&lt;!--more--&gt;&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;A private administrative interface&lt;/li&gt;
	&lt;li&gt;Seamless jQuery-backed test interface with few pageloads&lt;/li&gt;
	&lt;li&gt;Custom PDF reports, generated on the fly&lt;/li&gt;
	&lt;li&gt;A customer database with contact information&lt;/li&gt;
	&lt;li&gt;API endpoints for test generation&lt;/li&gt;
	&lt;li&gt;Integration with 3rd party e-commerce system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pansopie PC isn’t currently doing business.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>When to Develop Apps From Scratch</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2015/02/when-to-develop-apps-from-scratch/" rel="alternate" type="text/html" title="When to Develop Apps From Scratch" />
        <updated>2015-02-03T20:56:10+00:00</updated>
        <id>https://arnesonium.com/2015/02/when-to-develop-apps-from-scratch</id>
          <category term="management" />
        
          <category term="optimization" />
        
          <category term="programming" />
        
          <category term="publishing" />
        
          <category term="web-design" />
        
          <category term="web-development" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2015/02/when-to-develop-apps-from-scratch/">&lt;p&gt;I haven’t had time to write anything interesting for the blog this week, so instead check out Sebastian Green’s article, &lt;a href=&quot;http://www.developerdrive.com/2015/02/a-transparent-box-the-case-for-developing-from-scratch/&quot; target=&quot;_blank&quot;&gt;“A transparent box: the case for developing from scratch,”&lt;/a&gt; which has been published over at Developer Drive.&lt;/p&gt;

&lt;p&gt;Mr Green makes some great arguments for developing from scratch. Good software takes good planning, no matter what.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Philalethes E-Bulletin Online Reader</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2015/01/philalethes-e-bulletin-online-reader/" rel="alternate" type="text/html" title="Philalethes E-Bulletin Online Reader" />
        <updated>2015-01-12T22:33:11+00:00</updated>
        <id>https://arnesonium.com/2015/01/philalethes-e-bulletin-online-reader</id>
          <category term="epub" />
        
          <category term="freemasonry" />
        
          <category term="javascript" />
        
          <category term="php" />
        
          <category term="programming" />
        
          <category term="publishing" />
        
          <category term="web-development" />
        
          <category term="software-development" />
        
          <category term="case-study" />
        <content type="html" xml:base="https://arnesonium.com/2015/01/philalethes-e-bulletin-online-reader/">&lt;p&gt;I began working on the &lt;a href=&quot;http://freemasonry.org/ebulletin/&quot; title=&quot;Philalethes E-Bulletin&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;Philalethes E-Bulletin&lt;/em&gt;&lt;/a&gt; in the Fall of 2013, and published the first issue in January of 2014. The &lt;em&gt;E-Bulletin&lt;/em&gt; is published quarterly in EPUB and MOBI formats.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/wp-content/uploads/2014/12/Screenshot-from-2014-12-18-214441.png#left&quot; alt=&quot;Philalethes Society Seal&quot; width=&quot;203&quot; height=&quot;171&quot; class=&quot;alignright size-full wp-image-189&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s been a great learning experience. Not only have I learned a lot about editing, but I’ve really had to dive into how electronic publishing works. The intricacies of electronic book formats have become well-known to me.&lt;/p&gt;

&lt;p&gt;The Philalethes Society isn’t entirely comfortable with modern technology, however. Most complaints about the &lt;em&gt;E-Bulletin&lt;/em&gt; came from those who didn’t have e-book readers and weren’t comfortable installing software on their PC to handle a new file format. Because of this, I built an online e-book reader specifically for the &lt;em&gt;E-Bulletin&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The online e-book reader is based around the excellent &lt;a href=&quot;https://github.com/futurepress/epub.js/&quot; target=&quot;_blank&quot;&gt;EPUB.js library&lt;/a&gt;, with additional backend code written in PHP.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://freemasonry.org/ebulletin/reader/&quot; title=&quot;Philalethes E-Bulletin Online Reader&quot; target=&quot;_blank&quot;&gt;Click here to visit the &lt;em&gt;Philalethes E-Bulletin&lt;/em&gt; Online Reader.&lt;/a&gt;&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>An English-language Stemmer for OCaml</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2014/12/an-english-language-stemmer-for-ocaml/" rel="alternate" type="text/html" title="An English-language Stemmer for OCaml" />
        <updated>2014-12-29T16:47:38+00:00</updated>
        <id>https://arnesonium.com/2014/12/an-english-language-stemmer-for-ocaml</id>
          <category term="c" />
        
          <category term="ocaml" />
        
          <category term="opam" />
        
          <category term="programming" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2014/12/an-english-language-stemmer-for-ocaml/">&lt;p&gt;A stemming algorithm attempts to reduce words to their stem. For instance, “swimming” would be reduced to “swim”, and “avocados” would become “avocado”. This is useful in a number of situations, most especially in searching text. This library is a direct port of the Porter English stemming algorithm.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;It was one of my first OCaml projects. I wrote it back in 2003, when I was still new to the language. I had been spending a lot of time writing C libraries that were being called by Perl scripts for my day job. Perl has, or had, a cumbersome, messy interface to C that made such interfaces very difficult to write and maintain.&lt;/p&gt;

&lt;p&gt;When I discovered how easy it was to link C libraries into OCaml, I was overjoyed! This was my first attempt. Before reading further, check out my &lt;a href=&quot;https://github.com/pymander/ocaml-stemmer&quot;&gt;ocaml-stemmer library on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Updating the Code&lt;/h2&gt;

&lt;p&gt;Recently, while overhauling all of my publicly-available code, I decided to update my English-language stemmer for OCaml. It’s not a very large piece of code, but its age really shows. It wouldn’t compile cleanly with the latest version of OCaml. It looks like the code of somebody who hasn’t really grokked functional programming yet. Just look at this.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replace_end&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rule_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rule_list&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;hd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match_rule&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;apply_rule&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;replace_end&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tl&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ouch, right?&lt;/p&gt;

&lt;p&gt;I decided that the scary code would stand as a good message ((Or maybe I should say a good warning.)) to future functional programmers. For now, I just wanted to get this code to compile and not look messy. That ended up being easy.&lt;/p&gt;

&lt;h2&gt;Finding The Bug&lt;/h2&gt;

&lt;p&gt;Once I got it compiled cleanly, however, I found a bug. Back in 2003, I was big on test-driven development. I wrote tests for lots of code. The OCaml stemmer, it turns out, has been broken for quite a while. It doesn’t handle words with apostrophes correctly!&lt;/p&gt;

&lt;p&gt;I thought that fixing the bug it would be a challenge. However, I quickly I discovered in the OCaml manual that the &lt;code&gt;or&lt;/code&gt; operator was deprecated, and that &lt;code&gt;||&lt;/code&gt; should be used instead. Embarrassingly, the &lt;code&gt;or&lt;/code&gt; operator was deprecated back in 2002. That never should have been in the code! You can view the &lt;a href=&quot;https://github.com/pymander/ocaml-stemmer/commit/40cb816c4d97eea0d51de0f66533c09011f6cbd0&quot; target=&quot;_blank&quot;&gt;commit which fixed the bug here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;My Stemmer Library is Now on OPAM&lt;/h2&gt;

&lt;p&gt;This is my second library on &lt;a href=&quot;http://opam.ocaml.org/&quot; target=&quot;_blank&quot;&gt;OPAM&lt;/a&gt;, including my &lt;a href=&quot;http://arnesonium.com/2014/12/camlprime-now-on-opam/&quot; title=&quot;Camlprime Now on OPAM&quot; target=&quot;_blank&quot;&gt;prime number library&lt;/a&gt;. You can &lt;a href=&quot;http://opam.ocaml.org/packages/stemmer/stemmer.0.2/&quot; target=&quot;_blank&quot;&gt;view it on OPAM here&lt;/a&gt;.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Official Release of Libbucket 1.0.4</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2014/12/official-release-of-libbucket-1-0-4/" rel="alternate" type="text/html" title="Official Release of Libbucket 1.0.4" />
        <updated>2014-12-18T18:56:02+00:00</updated>
        <id>https://arnesonium.com/2014/12/official-release-of-libbucket-1-0-4</id>
          <category term="announcement" />
        
          <category term="c" />
        
          <category term="programming" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2014/12/official-release-of-libbucket-1-0-4/">&lt;p&gt;&lt;img src=&quot;https://img.shields.io/github/release/pymander/libbucket.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve tagged &lt;a href=&quot;https://github.com/pymander/libbucket/releases/tag/v1.0.4&quot; target=&quot;_blank&quot;&gt;version 1.0.4&lt;/a&gt; of libbucket over on GitHub. You can download a tarball &lt;a href=&quot;https://github.com/pymander/libbucket/archive/v1.0.4.tar.gz&quot; target=&quot;_blank&quot;&gt;at this link&lt;/a&gt;. If you’d like to read more about libbucket, see &lt;a href=&quot;http://arnesonium.com/2014/12/modernizing-libbucket/&quot; title=&quot;Modernizing libbucket&quot;&gt;my post from earlier this week&lt;/a&gt;.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Very handy edit:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can download version 1.0.4 of libbucket and an OpenPGP signature here:&lt;/p&gt;

&lt;blockquote&gt;&lt;a href=&quot;https://s3.amazonaws.com/arnesonium-downloads/libbucket-1.0.4.tar.gz&quot;&gt;libbucket-1.0.4.tar.gz&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://s3.amazonaws.com/arnesonium-downloads/libbucket-1.0.4.tar.gz.asc&quot;&gt;libbucket-1.0.4.tar.gz.asc&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;[caption id=”attachment_184” align=”aligncenter” width=”300”]&lt;img src=&quot;http://arnesonium.com/wp-content/uploads/2014/12/hakamairi-bucketflowers.png&quot; alt=&quot;I never realized how much bucket clip-art existed.&quot; width=&quot;300&quot; height=&quot;164&quot; class=&quot;size-full wp-image-184&quot; /&gt; I never realized how much bucket clip-art existed.[/caption]&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Modernizing libbucket</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2014/12/modernizing-libbucket/" rel="alternate" type="text/html" title="Modernizing libbucket" />
        <updated>2014-12-15T16:45:55+00:00</updated>
        <id>https://arnesonium.com/2014/12/modernizing-libbucket</id>
          <category term="c" />
        
          <category term="programming" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2014/12/modernizing-libbucket/">&lt;p&gt;If you’re here to learn about my experience in software development, you’ve probably poked around &lt;a href=&quot;https://github.com/pymander&quot;&gt;my GitHub page&lt;/a&gt;. One the older projects on there is &lt;a href=&quot;https://github.com/pymander/libbucket&quot;&gt;libbucket&lt;/a&gt;, a very fast dynamic string buffer library. I originally wrote it while working for Musician’s Friend, and was given permission to release it as an open sourced library in 2005.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://arnesonium.com/wp-content/uploads/2014/11/bucket-303359_640-300x293.png#right&quot; alt=&quot;Metaphorically similar to this kind of bucket.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Recently I decided to update the build system in the library, which was using an old version of autoconf and automake. I haven’t worked with those tools in a number of years. They are solid and flexible, but they’re also a confusing tangle of m4 macros and crazy shell scripts. Also, they change a lot.&lt;/p&gt;

&lt;p&gt;A few important things had changed. For instance, &lt;code&gt;aclocal&lt;/code&gt; wanted to read from &lt;code&gt;configure.ac&lt;/code&gt; instead of &lt;code&gt;configure.in&lt;/code&gt;. In addition, the &lt;code&gt;AM_INIT_AUTOMAKE&lt;/code&gt; macro was completely different, but the tool was nice enough to point me to &lt;a href=&quot;https://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation&quot;&gt;the relevant part of the automake manual&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Building a library is also a little different now than it was in 2002. &lt;a href=&quot;https://www.gnu.org/software/libtool/&quot;&gt;GNU Libtool&lt;/a&gt; is a great program for building dynamic and shared libraries correctly for Unix systems, but its usage is different now. Luckily, it spit out all of the information I needed to update things.&lt;/p&gt;

&lt;p&gt;One thing I didn’t quite figure out is how to get automake to recognize the &lt;code&gt;README.org&lt;/code&gt; file as satisfying its README requirement. I ended up with an initialization block in &lt;code&gt;configure.ac&lt;/code&gt; that looked like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-m4&quot;&gt;AC_INIT([libbucket], [1.0.4])
AC_CONFIG_SRCDIR([src/bucket.c])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign])
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see the unpleasant “cheat” on line 4. Sorry about that, world.&lt;/p&gt;

&lt;p&gt;After all of that mess, there were just a couple of small fixes to the documentation, which is written in GNU Texinfo, and the library compiled just fine.&lt;/p&gt;

&lt;p&gt;Unfortunately, I don’t have any tests. When I first developed libbucket, we had a proprietary test interface for C and C++ libraries at Musician’s Friend. That never got open sourced, so I had to remove it all before making the libbucket code public. Maybe tests are next.&lt;/p&gt;

&lt;p&gt;If you’d like to take a look at the changes I made, &lt;a href=&quot;https://github.com/pymander/libbucket/commit/6314493fb7c8397318ac4a8d10624159aab07204&quot;&gt;here’s the Git commit&lt;/a&gt;.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>OpenPGP.js and WordPress</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2014/12/openpgp-js-and-wordpress/" rel="alternate" type="text/html" title="OpenPGP.js and WordPress" />
        <updated>2014-12-03T16:14:51+00:00</updated>
        <id>https://arnesonium.com/2014/12/openpgp-js-and-wordpress</id>
          <category term="javascript" />
        
          <category term="php" />
        
          <category term="plugin" />
        
          <category term="wordpress" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2014/12/openpgp-js-and-wordpress/">&lt;p&gt;Near the end of November, I began fiddling with &lt;a href=&quot;http://openpgpjs.org/&quot; target=&quot;_blank&quot;&gt;OpenPGP.js&lt;/a&gt; and building a WordPress plugin. My goal is to create a method by which visitors can encrypt messages to me on my &lt;a href=&quot;http://arnesonium.com/contact/&quot; title=&quot;Contact&quot;&gt;Contact page&lt;/a&gt; using my public key.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;I finished up a pretty simple little plugin. You can &lt;a href=&quot;http://arnesonium.com/wordpress-openpgp/&quot; title=&quot;OpenPGP Form Encryption for WordPress&quot;&gt;view the details here&lt;/a&gt; or head straight to the &lt;a href=&quot;https://github.com/pymander/wordpress-openpgp&quot;&gt;GitHub project page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, when I finished earlier this week and decided to submit it to the WordPress Plugin Directory, I found that somebody had beat me to it by almost a month. I’ve taken a look at the code and it looks pretty good. You can check out my plugin, which was published as &lt;a href=&quot;https://wordpress.org/plugins/openpgp-form-encryption/&quot; target=&quot;_blank&quot;&gt;OpenPGP Form Encryption for Wordpress&lt;/a&gt;, and you can check out the other guy’s plugin, &lt;a href=&quot;https://wordpress.org/plugins/pgp-contact/&quot; target=&quot;_blank&quot;&gt;PGP Contact plugin&lt;/a&gt;.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Camlprime Now on OPAM</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2014/12/camlprime-now-on-opam/" rel="alternate" type="text/html" title="Camlprime Now on OPAM" />
        <updated>2014-12-02T22:19:09+00:00</updated>
        <id>https://arnesonium.com/2014/12/camlprime-now-on-opam</id>
          <category term="math" />
        
          <category term="ocaml" />
        
          <category term="opam" />
        
          <category term="programming" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2014/12/camlprime-now-on-opam/">&lt;p&gt;My first &lt;a href=&quot;http://opam.ocaml.org/&quot; target=&quot;_blank&quot;&gt;OCaml Package Manager (OPAM)&lt;/a&gt; submission has just been accepted. You can now find &lt;a href=&quot;http://arnesonium.com/2014/11/prime-number-library-for-ocaml/&quot; title=&quot;Prime Number Library for OCaml&quot;&gt;Camlprime, a prime number library&lt;/a&gt;, on &lt;a href=&quot;http://opam.ocaml.org/packages/camlprime/camlprime.0.5/&quot; target=&quot;_blank&quot;&gt;OPAM here&lt;/a&gt;.&lt;/p&gt;</content>
      </entry>
    
      <entry>
        
        <title>Prime Number Library for OCaml</title>
        <author>
          <name>Erik L. Arneson</name>
        </author>        
        <link href="https://arnesonium.com/2014/11/prime-number-library-for-ocaml/" rel="alternate" type="text/html" title="Prime Number Library for OCaml" />
        <updated>2014-11-13T17:08:39+00:00</updated>
        <id>https://arnesonium.com/2014/11/prime-number-library-for-ocaml</id>
          <category term="math" />
        
          <category term="ocaml" />
        
          <category term="programming" />
        
          <category term="software-development" />
        <content type="html" xml:base="https://arnesonium.com/2014/11/prime-number-library-for-ocaml/">&lt;p&gt;A couple of weeks ago, I cleaned up my prime number library for &lt;a href=&quot;https://ocaml.org/&quot;&gt;OCaml&lt;/a&gt;. This library has a number of primality-testing methods in it, but my favorite is the &lt;a href=&quot;http://jeremykun.com/2013/06/16/miller-rabin-primality-test/&quot;&gt;Miller-Rabin primality test&lt;/a&gt;. It’s fast and rather accurate.
&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;If you’d like to take a look at the library, please check out the &lt;a href=&quot;https://github.com/pymander/camlprime&quot;&gt;camlprime GitHub page&lt;/a&gt;. The library is pretty easy to use. If you download and compile the library, you’ll end up with a toplevel that you can play with.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;test.ml&lt;/code&gt; file has some examples of how to use the primality tests. However, my favorite thing about this library is that it includes a &lt;a href=&quot;https://www.haskell.org/haskellwiki/Lazy_evaluation&quot;&gt;lazy list&lt;/a&gt; implementation of prime numbers. The following example shows how to set up a lazy list of prime numbers proved using the MR algorithm in the toplevel.&lt;/p&gt;

&lt;div class=&quot;language-ocaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;open&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Num&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prime_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;miller_rabin&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_of_int&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prime_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;LazyList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;LazyList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;503&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Prime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nth&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prime_list&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4363&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The library is pretty fast, even for really large numbers. I’ve tested it on 300-digit prime numbers, and I’m sure it will scale to sizes much larger than that.&lt;/p&gt;

&lt;p&gt;Any thoughts or improvements? Let me know in the comments.&lt;/p&gt;</content>
      </entry>
    
</feed>
