• Installing Plerd from head with no root access

    Posted:

    This post is more of some admin notes as I try to get a clean install of plerd from github.

    First, you need a modern perl (I’m using perl 5.24 via plenv).

    You should install Carton next. It will make everything easier.

    $ git clone git@github.com:jmacdotorg/plerd.git $ cd plerd $ carton

    Create a new file called env.sh. Make it look like this:

    #!/bin/bash # source me: ./env.sh # export APP_HOME=[REPLACE WITH YOUR PATH TO plerd] export PERL5LIB=$APP_HOME/local/lib/perl5 export PATH=”$APP_HOME/local/bin:$PATH”

    Replace items within [] using appropriate values.
    Save this file and then source it:

    $ source ./env.sh

    Now you can run:

    $ perl Makefile.PL —PREFIX=./local $ make && make install

    I think there is a way to force plerd into the local/lib/perl5 structure. For now, I just moved these manually.

    $ mv -v local/share/perl/5.24.1/*pm local/lib/perl5/ $ mv -v local/share/perl/5.24.1/Plerd local/lib/perl5/

    You will find plerdall and plerdwatcher in ./local/bin and both should be in your PATH.

    Time to make the default plerd config:

    $ plerdall —init

    Go ahead and edit that file in the proscribed way.

    To run plerdall correctly, you will probably want to change into the newly created plerd directory. This will be inside the git sandbox but whatevs.

    $ cd plerd $ plerdall

    Interestingly, the following files were empty:

    atom.xml feed.json recent.xml

    Some of the tag/* files were also empty.

  • A Public Kaizen on Blogging

    Posted:

    Going through my old blog posts from over ten years ago has been a humbling experience. A good deal of my writing style was cloying and needy. Joe Michael Straczinski has suggested that to be a good writer, you need to burn about 100,000 words writing poorly. I think Joe was a quick study.

    Often, this blog attempted to provide insights into the tech industry. These attempts were meager and weak. At best, I only amplified common knowledge and at worst I put my ignorance on public display.

    A significant chunk of the blog corpus is reads like a kind of proto-Twitter. There is a lot of personal stuff that lacks context or perspective. It is tempting to attribute these shortcomings to the age of the writer, but there are many examples of great writers who manifested great skill early in their careers.

    These maudlin observations are an attempt at a ”kaizen”, which is a Japanese word meaning “improvement”. A kaizen event is a time dedicated away from normal activities to reflect on what went well and what could have been improved in you life and work.

    The outcome of my personal kaizen for this blog is to produce work of higher quality that provides better insights into whatever subject moves me. A good deal of my headspace is in boardgame design, but I also want to share what I’ve learned about software engineering in the web application space over these past twenty years.

    Here is the part of the post were I put a call to action like “subscribe to my atom feed” or “follow me on twitter!”. Instead, I will focus narrowly on my content and let the Deep Learning AI at search engines handle the marketing.

  • On Single-play games

    Posted:

    A friend of mine sent me a meme today featuring a picture of someone filling a cup using two spouts of a soda fountain at the same time. One spout was labelled “Legacy system” and the other “Literally every other game”. On the hand holding the cup was the name of a well-known game designer who is famous for producing legacy games.

    “Sick burn,” I remarked.

    However, this meme got me thinking more about Legacy and single-use games.

    Legacy games are versions of existing games with new rules and mechanics that permanently change the components of the game. This means that these kinds of games usually can only be played once (or if campaign-based, only played a set number of times). The most popular version of this kind of game is Legacy Pandemic, which now ships in seasons. This is to say, each season is an isolated campaign that players are expected to finish before going on to the next one.

    If you are a traditional or causal boardgammer, you may find the idea of destroying cards or marking up the playing board a startling idea. Let your mind be at ease; It is. However, legacy games are a subset of single-use games, many of which have been with us for some time.

    “Real life” escape rooms have become extremely popular. The idea of solving puzzles in real-team with your friends and family is quite fun for a certain class of people. This kind of entertainment is inherently single-use. Sure, you can try to go through the puzzle again, but it probably won’t be as much fun.

    It isn’t surprising that boardgames have tried to capture some of that fun at home using a variety of traditional boardgame elements (particularly cards). Games like the Exit series come to mind. My family has played a couple of these to great effect. Like their real-life counterparts, these boardgames are single-use.

    Recently, Z-Man games introduced a Choose Your Own Adventure IP-branded game that plays like one of the classic CYOA books I grew up reading. The designers did a great job of translating the experience of those books to a cooperative gaming environment. Some have complained that it isn’t much of a game, to which I agree. However, it was a fantastic, single-use activity.

    It only recently occurred to me that there is little new about the genre of single-use games. One of the most successful games of my youth was inherently single-use although it was careful never to point out this fact. Trivial Pursuit, with its admittedly large, but fixed collection of question-answer pairs, surely must be included in this group of games. Trivial Pursuit later sold new “editions” of thematically linked questions (e.g. the Silver Screen edition, the Baby Boomer edition, etc.) that pointed to the single-use nature of the core mechanic.

    Others have pointed out that criticism the “disposable” nature of single-use games ignores that most boardgames are played but a handful of times, even the wildly popular ones. If you can get a couple of hours out of game that you can’t play again, you have a story that will last a lifetime.

  • plerd-cli - an interactive tool for Plerd

    Posted:

    My self-imposed Twitter exile has already paid off with the creation of this little program: plerd-cgi. This is designed to be an interactive tool to “manage” your plerd instance. Currently, the tool can regenerate all your content or from your sources directory or just a single post. This is very helpful when you are on the host running plerd and you are changing stylesheets or other settings.

    I will ping the plerd development team (hi, Jmac) and see if there is interest in adding this tool to the plerd/bin directory (which is where I have it).

    Increasing, my version of plerd is drifting from the released version. When plerd gets tags (jmac’s re-implementation of a feature I contributed), then I will try to merge these codebases together again.

    From previous post, you can see that I am experimenting with managing photos. Plerd’s killer feature is its integration with Dropbox. This really enables a powerful and flexible blogging platform for those used to composing in text editors, like me.

    #!/usr/bin/env perl
    
    use warnings;
    use strict;
    
    use FindBin;
    use lib ("$FindBin::Bin/../lib");
    
    use Cwd ('abs_path');
    use File::Basename;
    use Getopt::Long;
    use Path::Class::File;
    use YAML qw( LoadFile );
    
    use Plerd;
    
    our %gKnownCommands =
        ('regen_all' => \&cmd_regenerate_all, 'regen' => \&cmd_regenerate_file, 'help' => \&cmd_help);
    
    main();
    exit;
    
    #-----
    # Subs
    #-----
    sub main {
        my $opts = usage();
    
        my $plerd = init_plerd();
    
        # Only do one command
        while (my ($command, $action) = each %gKnownCommands) {
            if (defined $opts->{$command}) {
                return $action->($plerd, $opts);
            }
        }
    
        return;
    } # end sub main
    
    
    sub usage {
        my %opts;
    
        GetOptions(
            "help"        => \$opts{help},
            "R|regen-all" => \$opts{regen_all},
            "r|regen:s"   => \$opts{regen},
            "v|verbose"   => \$opts{verbose},
        );
    
        if ($opts{help}) {
            dump_usage();
            exit;
        }
    
        my $has_command = 0;
        for my $command (keys %gKnownCommands) {
            $has_command |= defined $opts{$command};
        }
    
        if (!$has_command) {
            die("No command given.  See --help for details.\n");
        }
    
        return \%opts;
    } # end sub usage
    
    
    sub dump_usage {
        print <<"EOT";
    $0 - command line interface to plerd
    
    USAGE:
    
      $0 [OPTIONS]
    
    OPTIONS:
    
      --help           # this screen
      --verbose        # provide more verbose output
      --regen-all      # regenerate all HTML files from known sources
      --regen FILE     # regenerate just this source file
    
    
    EOT
    
    } # end sub dump_usage
    
    
    sub init_plerd {
        my ($opts) = @_;
    
        my $conf_file = "$FindBin::Bin/../conf/plerd.conf";
        if (!-e $conf_file) {
            die("Cannot find '$conf_file'\n");
        }
    
        my $config_ref = LoadFile($conf_file);
        my $plerd      = Plerd->new($config_ref);
    
        return $plerd;
    } # end sub init_plerd
    
    
    sub cmd_help {
        my ($plerd, $opts) = @_;
        dump_usage();
        return;
    } # end sub cmd_help
    
    
    sub cmd_regenerate_all {
        my ($plerd, $opts) = @_;
    
        my $start = time();
        if ($opts->{verbose}) {
            print("Regenerating all content.  This may take a while.\n");
        }
    
        $plerd->publish_all();
    
        if ($opts->{verbose}) {
            printf("Regeneratation completed in %0.2f minutes.\n", (time() - $start) / 60);
        }
    
    } # end sub cmd_regenerate_all
    
    
    sub cmd_regenerate_file {
        my ($plerd, $opts) = @_;
    
        my $source_file = abs_path($opts->{regen});
    
        if (!-e $source_file) {
            die("Cannot find '$source_file'\n");
        }
    
        # is the source file within the source_directory?
        my $dirname = dirname($source_file);
        if ($dirname ne $plerd->source_directory) {
            die(sprintf(
                    "File '%s' does not appear to be in the source directory '%s'\n",
                    $source_file, $plerd->source_directory
                )
            );
        }
    
        if ($opts->{verbose}) {
            print("Publishing '$source_file'\n");
        }
    
        my $post = Plerd::Post->new(
            source_file => Path::Class::File->new($source_file),
            plerd       => $plerd
        );
        eval {
            $post->publish;
            1;
        } or do {
            die(sprintf("Could not publish '%s': %s\n", $source_file, $@));
        };
    
        # Publishing this new post triggers updates on these other pages
        for my $action (
            'publish_tag_indexes', 'publish_archive_page',
            'publish_recent_page', 'publish_rss',
            'publish_jsonfeed'
        ) {
            if ($opts->{verbose}) {
                print("-> $action\n");
            }
            $plerd->$action;
        }
    
        if ($opts->{verbose}) {
            printf("View your new post here: %s\n", $post->uri);
        }
    
        return;
    } # end sub cmd_regenerate_file
    
    

    UPDATE: I spoke to Jmac about this and he pointed out his intention for the exisiting plerdall program to fill this niche. Additionally, the publish all functionality is already there. So I will talk a crack at porting what I have here when I am up and running with the current tip of plerd.

  • Configuring emacs25 with perltidy, an epic adventure

    Posted:

    It’s a simple thing to ask. You want emacs to nicely indent your code. Emacs comes with two perl editing modes: perl-mode and cperl-mode. For many years, I have used cperl-mode happily. However, $dayjob prefers the way perltidy arranges code and I have come to agree.

    If you would like to get perltidy to format your code in emacs, you will need to do the following:

    • install emacs25
    • install Perl::Tidy
    • install tramp
    • install perltidy.el

    This is a lot more work than it should be, but this is what I needed to do to get this working under Debian 9.4. Maybe your mileage will vary.

    Installing emacs25

    This is pretty easy to do on debian:

      $ sudo apt-get install emacs25-nox
    

    If you want the X version of emacs, leave off -nox from the package name.

    Installing Perl::Tidy

    This too is pretty straight forward for perlers:

      $ sudo cpan install Perl::Tidy
    

    There are no XS parts of Perl::Tidy so this usually goes fast. Note that if you are using something like Perlbrew or plenv, you probably still want to globably install Perl::Tidy rather than make this a per-project module.

    Perltidy’s default styling can be overridden by a local ~/.perltidyrc. Here’s mine:

    # -*-conf-unix-*-
    # This is how $dayjob thinks of the world and I agree
    -l=100
    -i=4
    -ci=4
    # --outdent-labels --outdent-label-characters=2
    --opening-brace-always-on-right
    --cuddled-else
    # --break-after-all-operators
    # exception: "or" and "and" read better at the start of the line
    -wbb="or and ->"
    # ToDo: Currently we break after these operators:
    --want-break-after='. , && || **= += *= &= <<= &&= -= /= |= >>= ||= %= ^= x= .='
    --want-break-before='or and -> ? : << >> -> // % + - * / x != == >= <= =~ < > | &'
    --no-break-at-old-ternary-breakpoints
    --no-line-up-parentheses
    --closing-side-comments
    --closing-side-comment-prefix="# end"
    -cscl="sub : BEGIN END"
    -csci=3
    # Allow up to two consecutive blank lines.
    --maximum-consecutive-blank-lines=3
    --no-blanks-before-subs
    --no-blanks-before-comments
    --minimum-space-to-comment=1
    -vt=2   # Maximal vertical tightness
    -cti=0  # No extra indentation for closing brackets
    --paren-tightness=2   # High parenthesis tightness
    -bt=1   # Medium brace tightness
    -sbt=1  # Medium square bracket tightness
    -bbt=1  # Medium block brace tightness
    --no-outdent-long-quotes
    --no-outdent-long-comments
    --no-space-for-semicolon
    --format-skipping
    --static-side-comments
    --static-side-comment-prefix="##"
    

    Installing tramp

    Tramp is a dependency of the perltidy emacs package. Unfortunately, it does not appear to come with the Debian emacs25 package, nor did I find a debian package for this. This leaves us with a from-source code install.

    You will need autoconf:

      $ sudo apt-get install autoconf
    

    Clone the git repo into a convenient directory (e.g. ~/src/emacs):

       $ git clone git://git.savannah.gnu.org/tramp.git
    

    And then build it:

      $ cd tramp && autoconf && make && make check
    

    There were a few unit test failures, but I ignored them.

    Now let emacs know about this package by adding the following lines to ~/.emacs:

      ;;-------------------------------------------------------------------------------------------------
      ;; tramp stuff 
      (add-to-list 'load-path "~/src/emacs/tramp/lisp/")
      (add-to-list 'Info-directory-list "~/src/emacs/tramp/info/")
      (require 'tramp)
    

    Be sure to get the paths right in those add-to-list directives.

    Installing perltidy.el

    If you made it this far, you’re a linux/unix pro! The last step is easy.

      $ mkdir -p ~/.emacs.d/lisp ; wget -O ~/.emacs/lisp/perltidy.el https://www.emacswiki.org/emacs/download/perltidy.el
    

    This adds the perltidy lisp bindings to your .emacs.d directory of local packages. Change the paths to reflect your organization scheme.

    If you have not yet done so, tell emacs about your local emacs packages by adding the following to ~/.emacs:

      (add-to-list 'load-path "~/.emacs.d/lisp/")
    

    FINAL STEP: Tell emacs about the perltidy package by editing ~/.emacs

    ;;-------------------------------------------------------------------------------------------------
    ;; perltidy
    (require 'perltidy)
    

    Mostly, I use M-x perltidy-dwim on a buffer to indent it, but here’s how to bind that operation to the F12 key:

    (global-set-key (kbd "") 'perltidy-dwim)
    

    I hope you guessed that this line is added to your ~/.emacs file after the require line.

    I hope this makes your life of indenting perl code in emacs all the more pleasant.

  • A New Hope

    Posted:

    Something happened on Twitter today. Rather, something happened to my relationship with Twitter today.

    I am taking a break from the platform for a while.

    This isn’t because I got into a fight with someone online or discovered some new terrible business practice of Twitter. This flight from social media is driven by two personal things.

    The first is my own dissatisfaction at my constant use of Twitter. Twitter provides a quick diversion when I have less than five minutes to kill. I now realize that I need to embrace that boredom and find a more creative outlet for it. That outlet may even just be whining on this blog in 140 character chunks, but at least it will be something disconnected from a larger, dumber narrative that I do not control.

    The other factor is that Twitter is not just depressing me or triggering outrage in me, it is now filling me with despair. Despair is a very potent poison that is best left unopened.

    I hope my vacation will push me to work on Plerd stuff more and this blog. I have long been meaning to discourse on what I think modern web applications should look like from the server and client side. Plus, there are a million little tech factoids that I should have been recording here that are now lost to time.

    Life is short and there are a lot of books I have not yet read.

    UPDATE: Just a note, mostly for me. This post was composed on iOS with the Textastic editor. It features dropbox integretion, which is how Plerd gets articles to post. Textastic does not yet support spell checking, which is a feature I demonstrably need. I guess I can limp along with Google for a bit.

  • Testing network speed with raspberry pi

    Posted:

    This is a quick hack to test the Internet connection speed of your raspberry pi running rasbian linux.

    As you may know, I have a small farm of RPIs doing SETI@Home work. I have one head node that all that traffic flows through. This simplifies configuration and makes the farm portal. Here’s an architecture diagram via emacs artist-mode.

                                      +-------+
                                 -----+ node1 |
                                 |    +-------+
                                 |
      +--------+   +---------+   |    +-------+
      | Public |---| Pi Head |---|----+ node2 |
      +--------+   +---------+   |    +-------+
                                 |
                                 |    +-------+
                                 -----+ node3 |
                                      +-------+
    

    I was worried that perhaps the traffic from my six worker nodes was overwhelming the WiFi adapter of my head node. There are two approaches I used to do this.

    The first is to look at the performace of short-term bursts. This will give me a flavor for the peak capacity provided by the head node’s built-in WiFi adapter. To do this I need nload (a terminal program that provides histograms of network traffic per adapter) and wget.

    I open one terminal and run nload -i wlan0 (I do not use predictable interface names because I am ancient). Then I open a second terminal and run wget to fetch a large file. Fitting, the rasbian image is quite adequate for this.

    wget -O /dev/null https://downloads.raspberrypi.org/raspbian_latest
    

    Don’t worry about disk space. This command throws all the fetch data into the bit bucket.

    My head node is about 4-6 meters from the WiFi access point in my home. I get about 40 - 45 MBit/s on average from this load. Yes, there are a lot of reasons why the load may be delivered as consistently as in a lab setting, but this will give you a flavor for the capacity of your RPI’s WiFi service.

  • A systemd service file for plerdwatcher and more

    Posted:

    So you have plerd all happy on your system. You run plerdwatch start and your off to the races. But what happens if your machine reboots? You need to restart both Dropbox and plerdwatcher.

    If you are on a linux box that supports systemd, you’re in luck.

    The following file will restart dropbox for you (you will need to change {USER} to username of the account running dropbox).

    [Unit]
    Description=Dropbox as a system service
    After=local-fs.target network.target
    
    [Service]
    Type=simple
    User={USER}
    ExecStart=/usr/bin/env "/home/{USER}/.dropbox-dist/dropboxd"
    Restart=on-failure
    RestartSec=1
    
    [Install]
    WantedBy=multi-user.target
    
    

    This should be copied in /etc/systemd/system/dropbox.service.

    The plerdwatcher unit file is a little more involved since on my machine, I run plerd using plenv. Here is the file:

    [Unit]
    Description=Plerd daemon that monitors incoming posts and handles webmentions
    Requires=network.target
    After=network.target
    
    [Service]
    Type=forking
    TasksMax=infinity
    User={USER}
    WorkingDirectory=/home/{USER}/src/plerd
    ExecStart=/bin/bash -lc "cd /home/{USER}/src/plerd && PERL5LIB=/home/{USER}/src/plerd/local/lib/perl5 bin/plerdwatcher start"
    ExecStop=/bin/bash -lc "cd /home/{USER}/src/plerd && PERL5LIB=/home/{USER}/src/plerd/local/lib/perl5 bin/plerdwatcher stop"
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    

    As with the previous file, you will need to replace {USER} with your account name. My installation of plerd is in my home directory in a directory called ‘src’. Inside of the plerd folder, I have a local directory containing Perl libraries needed for Plerd built for the version of Perl I run plerd with (5.26.1).

    You may need to tinker with this scripts a bit, but this should help you get started.

  • Taskboy Blogging again for the first time

    Posted:

    Welcome to my new blog. It is powered by Plerd, which is a OSS project I contribute to.

    More details later.

    This blog is also made by computer and powered by keys. You need a little humor in your blog.

    — My Son, Angus