Hacker Public Radio

A daily show hosted the community on topics that are of interest to hackers and hobbyists.
Hacker Public Radio


Hacker Public Radio is an podcast that releases shows every weekday Monday through Friday. Our shows are produced by the community (you) and can be on any topic that are of interest to hackers and hobbyists.

Link: hackerpublicradio.org/about.php




HPR3045: OSS compliance with privacy by default and design

Apr 3, 2020


The GDPR (General Data Protection Regulation) was enacted by the European Community in 2016, and began to be enforced in 2018. Since this covers a large segment of the Internet users, and other jurisdictions are looking at similar legislation this talk is a timely look at what is required and how Open Source Software can meet the legal requirements. https://www.zwilnik.com/?page_id=1096

Links: https://redaktor.me/apconf/ https://archive.org/details/apconf-talks/Talk6_Cristina_compressed.mov https://xwiki.com/en/company/who-we-are/ https://en.wikipedia.org/wiki/General_Data_Protection_Regulation https://developercertificate.org/ https://en.wikipedia.org/wiki/Fediverse https://www.zwilnik.com/?page_id=1096

HPR3044: mocp snooze tip

Apr 2, 2020


I use cordless headphones, I find this very handy when I want mocp to play for a set time then pause.

Commands used

Ctrl + r, to quickly find the command

sleep 10m && mocp -G

sleep 10m && mocp -M ~/.moc/audiobooks -G

sleep 5h && iplayer-url

HPR3043: How I record for HPR

Apr 1, 2020


Sentry BT250 Bluetooth Headphones w/ mic

F-Droid - free open source apps for Android

Audio Recorder from F-Droid
Features: Mute incoming call audio while recording Variety of format encoding ogg (default) wav flac m4a mp3 opus

X-plore Android file explorer

Audacity Amplify tool Bass and Treble tool

HPR3042: The COVID-19 Work From Home Stream - Day 0

Mar 31, 2020


Tuesday 17.03.2020

Guests: honkeymagoo, crvs, and Thaj

How likely we are to get COVID-19 Should we invest while the market is down How bad is the internet infrastructure in the US Learning Python Grasshopper Learn Python tne Hard Way Excercism Klaatu's Programming Book Growing plants That Audiobook Club though... Video games Single Board Computers OpenBSD on Raspberry Pi Why haven't you done a show about that Thaj? Emacs and org-mode Nano for the win

HPR3041: How to use GNU Autotools

Mar 30, 2020


I found a great article on this topic here: https://opensource.com/article/19/7/introduction-gnu-autotools, so please refer to that as show notes.

Page included by Ken, as permitted by cc-by-sa

Introduction to GNU Autotools

Have you ever downloaded the source code for a popular software project that required you to type the almost ritualistic ./configure; make && make install command sequence to build and install it? If so, you’ve used GNU Autotools. If you’ve ever looked into some of the files accompanying such a project, you’ve likely also been terrified at the apparent complexity of such a build system.

Good news! GNU Autotools is a lot simpler to set up than you think, and it’s GNU Autotools itself that generates those 1,000-line configuration files for you. Yes, you can write 20 or 30 lines of installation code and get the other 4,000 for free.

Autotools at work

If you’re a user new to Linux looking for information on how to install applications, you do not have to read this article! You’re welcome to read it if you want to research how software is built, but if you’re just installing a new application, go read my article about installing apps on Linux.

For developers, Autotools is a quick and easy way to manage and package source code so users can compile and install software. Autotools is also well-supported by major packaging formats, like DEB and RPM, so maintainers of software repositories can easily prepare a project built with Autotools.

Autotools works in stages:

First, during the ./configure step, Autotools scans the host system (the computer it’s being run on) to discover the default settings. Default settings include where support libraries are located, and where new software should be placed on the system. Next, during the make step, Autotools builds the application, usually by converting human-readable source code into machine language. Finally, during the make install step, Autotools copies the files it built to the appropriate locations (as detected during the configure stage) on your computer.

This process seems simple, and it is, as long as you use Autotools.

The Autotools advantage

GNU Autotools is a big and important piece of software that most of us take for granted. Along with GCC (the GNU Compiler Collection), Autotools is the scaffolding that allows Free Software to be constructed and installed to a running system. If you’re running a POSIX system, it’s not an understatement to say that most of your operating system exists as runnable software on your computer because of these projects.

In the likely event that your pet project isn’t an operating system, you might assume that Autotools is overkill for your needs. But, despite its reputation, Autotools has lots of little features that may benefit you, even if your project is a relatively simple application or series of scripts.


First of all, Autotools comes with portability in mind. While it can’t make your project work across all POSIX platforms (that’s up to you, as the coder), Autotools can ensure that the files you’ve marked for installation get installed to the most sensible locations on a known platform. And because of Autotools, it’s trivial for a power user to customize and override any non-optimal value, according to their own system.

With Autotools, all you need to know is what files need to be installed to what general location. It takes care of everything else. No more custom install scripts that break on any untested OS.


Autotools is also well-supported. Hand a project with Autotools over to a distro packager, whether they’re packaging an RPM, DEB, TGZ, or anything else, and their job is simple. Packaging tools know Autotools, so there’s likely to be no patching, hacking, or adjustments necessary. In many cases, incorporating an Autotools project into a pipeline can even be automated.

How to use Autotools

To use Autotools, you must first have Autotools installed. Your distribution may provide one package meant to help developers build projects, or it may provide separate packages for each component, so you may have to do some research on your platform to discover what packages you need to install.

The primary components of Autotools are:

automake autoconf make

While you likely need to install the compiler (GCC, for instance) required by your project, Autotools works just fine with scripts or binary assets that don’t need to be compiled. In fact, Autotools can be useful for such projects because it provides a make uninstall script for easy removal.

Once you have all of the components installed, it’s time to look at the structure of your project’s files.

Autotools project structure

GNU Autotools has very specific expectations, and most of them are probably familiar if you download and build source code often. First, the source code itself is expected to be in a subdirectory called src.

Your project doesn’t have to follow all of these expectations, but if you put files in non-standard locations (from the perspective of Autotools), then you’ll have to make adjustments for that in your Makefile later.

Additionally, these files are required:


You don’t have to actively use the files, and they can be symlinks to a monolithic document (like README.md) that encompasses all of that information, but they must be present.

Autotools configuration

Create a file called configure.ac at your project’s root directory. This file is used by autoconf to create the configure shell script that users run before building. The file must contain, at the very least, the AC_INIT and AC_OUTPUT M4 macros. You don’t need to know anything about the M4 language to use these macros; they’re already written for you, and all of the ones relevant to Autotools are defined in the documentation.

Open the file in your favorite text editor. The AC_INIT macro may consist of the package name, version, an email address for bug reports, the project URL, and optionally the name of the source TAR file.

The AC_OUTPUT macro is much simpler and accepts no arguments.

AC_INIT([penguin], [2019.3.6], [seth@example.com])

If you were to run autoconf at this point, a configure script would be generated from your configure.ac file, and it would run successfully. That’s all it would do, though, because all you have done so far is define your project’s metadata and called for a configuration script to be created.

The next macros you must invoke in your configure.ac file are functions to create a Makefile. A Makefile tells the make command what to do (usually, how to compile and link a program).

The macros to create a Makefile are AM_INIT_AUTOMAKE, which accepts no arguments, and AC_CONFIG_FILES, which accepts the name you want to call your output file.

Finally, you must add a macro to account for the compiler your project needs. The macro you use obviously depends on your project. If your project is written in C++, the appropriate macro is AC_PROG_CXX, while a project written in C requires AC_PROG_CC, and so on, as detailed in the Building Programs and Libraries section in the Autoconf documentation.

For example, I might add the following for my C++ program:

AC_INIT([penguin], [2019.3.6], [seth@example.com])

Save the file. It’s time to move on to the Makefile.

Autotools Makefile generation

Makefiles aren’t difficult to write manually, but Autotools can write one for you, and the one it generates will use the configuration options detected during the ./configure step, and it will contain far more options than you would think to include or want to write yourself. However, Autotools can’t detect everything your project requires to build, so you have to add some details in the file Makefile.am, which in turn is used by automake when constructing a Makefile.

Makefile.am uses the same syntax as a Makefile, so if you’ve ever written a Makefile from scratch, then this process will be familiar and simple. Often, a Makefile.am file needs only a few variable definitions to indicate what files are to be built, and where they are to be installed.

Variables ending in _PROGRAMS identify code that is to be built (this is usually considered the primary target; it’s the main reason the Makefile exists). Automake recognizes other primaries, like _SCRIPTS, _DATA, _LIBRARIES, and other common parts that make up a software project.

If your application is literally compiled during the build process, then you identify it as a binary program with the bin_PROGRAMS variable, and then reference any part of the source code required to build it (these parts may be one or more files to be compiled and linked together) using the program name as the variable prefix:

bin_PROGRAMS = penguin
penguin_SOURCES = penguin.cpp

The target of bin_PROGRAMS is installed into the bindir, which is user-configurable during compilation.

If your application isn’t actually compiled, then your project doesn’t need a bin_PROGRAMS variable at all. For instance, if your project is a script written in Bash, Perl, or a similar interpreted language, then define a _SCRIPTS variable instead:

bin_SCRIPTS = bin/penguin

Automake expects sources to be located in a directory called src, so if your project uses an alternative directory structure for its layout, you must tell Automake to accept code from outside sources:

AUTOMAKE_OPTIONS = foreign subdir-objects

Finally, you can create any custom Makefile rules in Makefile.am and they’ll be copied verbatim into the generated Makefile. For instance, if you know that a temporary value needs to be replaced in your source code before the installation proceeds, you could make a custom rule for that process:

all-am: penguin
        touch bin/penguin.sh
penguin: bin/penguin.sh
        @sed "s|__datadir__|@datadir@|" $< >bin/$@

A particularly useful trick is to extend the existing clean target, at least during development. The make clean command generally removes all generated build files with the exception of the Automake infrastructure. It’s designed this way because most users rarely want make clean to obliterate the files that make it easy to build their code.

However, during development, you might want a method to reliably return your project to a state relatively unaffected by Autotools. In that case, you may want to add this:

        @rm config.status configure config.log
        @rm Makefile
        @rm -r autom4te.cache/
        @rm aclocal.m4
        @rm compile install-sh missing Makefile.in

There’s a lot of flexibility here, and if you’re not already familiar with Makefiles, it can be difficult to know what your Makefile.am needs. The barest necessity is a primary target, whether that’s a binary program or a script, and an indication of where the source code is located (whether that’s through a _SOURCES variable or by using AUTOMAKE_OPTIONS to tell Automake where to look for source code).

Once you have those variables and settings defined, you can try generating your build scripts as you see in the next section, and adjust for anything that’s missing.

Autotools build script generation

You’ve built the infrastructure, now it’s time to let Autotools do what it does best: automate your project tooling. The way the developer (you) interfaces with Autotools is different from how users building your code do.

Builders generally use this well-known sequence:

$ ./configure
$ make
$ sudo make install

For that incantation to work, though, you as the developer must bootstrap the build infrastructure. First, run autoreconf to generate the configure script that users invoke before running make. Use the –install option to bring in auxiliary files, such as a symlink to depcomp, a script to generate dependencies during the compiling process, and a copy of the compile script, a wrapper for compilers to account for syntax variance, and so on.

$ autoreconf --install
configure.ac:3: installing './compile'
configure.ac:2: installing './install-sh'
configure.ac:2: installing './missing'

With this development build environment, you can then create a package for source code distribution:

$ make dist

The dist target is a rule you get for "free" from Autotools.
It’s a feature that gets built into the Makefile generated from your humble Makefile.am configuration. This target produces a tar.gz archive containing all of your source code and all of the essential Autotools infrastructure so that people downloading the package can build the project.

At this point, you should review the contents of the archive carefully to ensure that it contains everything you intend to ship to your users. You should also, of course, try building from it yourself:

$ tar --extract --file penguin-0.0.1.tar.gz
$ cd penguin-0.0.1
$ ./configure
$ make
$ DESTDIR=/tmp/penguin-test-build make install

If your build is successful, you find a local copy of your compiled application specified by DESTDIR (in the case of this example, /tmp/penguin-test-build).

$ /tmp/example-test-build/usr/local/bin/example
hello world from GNU Autotools Time to use Autotools

Autotools is a great collection of scripts for a predictable and automated release process. This toolset may be new to you if you’re used to Python or Bash builders, but it’s likely worth learning for the structure and adaptability it provides to your project.

And Autotools is not just for code, either. Autotools can be used to build Docbook projects, to keep media organized (I use Autotools for my music releases), documentation projects, and anything else that could benefit from customizable install targets.

HPR3040: Why use GNU Autotools

Mar 27, 2020


GNU Autotools is a build system that helps you distribute your code in a predictable and reliable way. Build systems offer many benefits, including:

Standard and automate-able build process hooks into packaging systems (RPM, DEB, Slackbuilds, Flatpak, Snap, and so on) version reporting build for various OSes you get lots of code to handle every possible corner case, for free with a single configuration, you can build your project as the developer, build it for packagers, and enable users to build it for themselves

Next up: how to use GNU Autotools

HPR3039: Making a Raspberry Pi status display

Mar 26, 2020



I have had a project on my To Do list for a while: to make a status display from a Raspberry Pi. My vision was to show the state of various things including some HPR stuff, and I had imagined setting up a Pi with a monitor and controlling it over SSH.

I started on the project over the Christmas period 2019. I have a Raspberry Pi 3A+, which is a sort of souped-up Pi Zero, which I bought on a whim and hadn’t found a use for (Yannick reviewed this RPi model in show 2711). I also had an old square Dell monitor from about 15 years ago which still worked (at least to begin with).

I had imagined I’d write some software of my own with a web front end which ran various tasks to monitor things.

However, in my researches I came across MagicMirror2 which I thought I might be able to use instead of writing my own thing.

Long notes

I have provided detailed notes as usual for this episode, and these can be viewed here.

Links JavaScript programming language: Wikipedia entry Node.js JavaScript runtime environment: Website Wikipedia entry Electron software framework: Website Wikipedia entry MagicMirror2: GitHub page Website List of third-party modules Resources: Example files: config.js custom.css

HPR3038: Solo Magic

Mar 25, 2020


This episode outlines my single-player mod for the Magic: The Gathering card game.

HPR3037: Ambient recording at Union Station

Mar 24, 2020


This was recorded in the main hall at Union Station in Chicago, Illinois.
There was a brief security announcement about watching for bags or package left unattended.

HPR3035: Decentralised Hashtag Search and Subscription in Federated Social Networks

Mar 20, 2020

HPR3034: How to bridge Freenode IRC rooms to Matrix.org

Mar 19, 2020



Clacke - HPR Episode 2169 on Matrix Dave Lee - Helped a great deal in getting me on board with Matrix bridging. Check out his other podcasts at The Other Side Podcast Network

Matrix.org is a Free, open source, and decentralized messaging system. One of the strong points of this system is its ability to bridge multiple protocols together into one interface.


Bridging to Freenode's IRC server is built into Matrix.org. If you already have a registered Nick on Freenode it is a simple process to associate your Matrix and Freenode accounts.

Steps to bridge to a Freenode IRC room

Start a direct message with @freenode_NickServ:matrix.org and send the command identify nick pass (replacing nick and pass with your credentials). Direct message @appservice-irc:matrix.org with the command !storepass nick:pass Join the room #freenode_#oggcastplanet:matrix.org. You can really join any room on freenode with #freenode_#CHANNAME:matrix.org PROFIT!!!!

HPR3033: 32 Bit Time Travel

Mar 18, 2020


For show notes, please visit https://linuxinlaws.eu

HPR3032: piCore on a Raspberry Pi 1 Model B

Mar 17, 2020


In this episode, I discuss how I revived my Raspberry Pi 1 Model B using piCore, a specialized version of Tiny Core Linux for the Raspberry Pi, on a 128 MB SD card that I had laying around. I also mention nanoBSD and Alpine Linux as possible alternatives to try out.

Tiny Core Linux

piCore Releases


Alpine Linux

HPR3031: Daniel Persson - Me? Me!

Mar 16, 2020


Talking about my history, forgot to talk about my open-source interests and different projects I’m a part of.

If you want to know more about me you could follow any of the links below.





HPR3030: My new Samsung tablet

Mar 13, 2020


Samsung Galaxy Tab A 10.5 inch 2018 Tablet at 3:30
Amazon link

Nexus 7 at 3:50

New tablet Battery at 5:20
Lithium Polymer batteries, 7300 mAh capacity with claimed 15 hours of video playback on one charge. It seems to charge surprisingly quickly.

Wikipedia entry for Edinburgh City Bypass at 9:30

Eye strain at 14:07

Bluetooth Ear buds at 15:15
Similar to these: Amazon link

Bluetooth speaker at 16:52
Amazon link

Bluetooth keyboard at 22:35
Amazon link

Additional thoughts after recording this episode

Closing one eye seems to solve the problem though not very practical. It doesn’t seem to matter which eye I close.

Doesn’t seem to bother me with the other 8” Samsung tablet or any other tablet / phone.

Counter intuitively increasing the brightness makes things better

Searching for eye strain and Samsung brought up one or two results of people saying a similar thing to myself; one person commenting that they were fed up of people telling them to get an eye test and like myself they do not have this problem with any other device.

HPR3029: At Union Station with a train delay

Mar 12, 2020


I was waiting for the Metra train, when there was an announcement that the train would be late due to a server failure.

HPR3028: Monads and Haskell

Mar 11, 2020


This is basically a transcript of the post I wrote on the subject which I host here It has a bit more than what I talked about

Join in Haskell

join is a monadic operation, instead of working only on lists, it works on monads and has the signature:

join :: Monad m => m ( m a ) -> (m a)

In effect it joins or merges two successive monad applications into a single monad application. But join is not part of the canonical monad definition, which is given by:

return :: Monad m => a -> m a` ; and` (>>=) :: Monad m => m a -> ( a -> m b ) -> m b

A good or rather trivial way to think of the relationship between return join and (>>=) is that in essence, since each monad is a functor, then what (>>=) does is that it maps the second argument over the first argument, and then uses join to merge the two applications of the monad constructor, i.e.:

(x >>= f) = join $ fmap f x

However, join needs to be constructed from return and (>>=). The naive solution is that we want to trick (>>=) to let us apply a function that does not pile up yet another m onto our initial type m (m a) and surprisingly, this will actually work if we let

join x = (x >>= id)

Initially this is surprising since id has the signature (c -> c) instead of the necessary a -> m b! However, when c is not an atomic type, but rather of the form m d for some (maybe atomic) type d, then we actually have the signature m d -> m d, and if we bind type a to m d and type b to d, we obtain id with actual type signatuare a -> m b, and it can indeed be used as the second argument of (>>=), and everything actually makes sense.

Now style is important and so we can do an eta reduction on this, to get a point-free implementation by simply binding the second argument of >>=:

join = (>>= id)

This is all fine and well for the type number, and it does work, but it's also important to understand how it works, so let's see it in a simple example, using the Maybe monad. So let's start by refreshing the implementation of the monad instance:

instance Monad Maybe where (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b (>>=) Nothing _ = Nothing (>>=) (Just x) f = f x return :: a -> Maybe a return = Just

So let's now go through the successive bindings when performing (>>=id):

Just x = Just (Just 2) => x = Just 2 Just x >>= id = id x = x x = Just 2

This example is pretty much verbatim the same thing for the Either monad and many other monads that follow a similar principle, so let's look at a bit more of a complex example. Let's look at the List monad:

instance Monad List where

(>>=) :: [a] -> (a -> [b]) -> [b] (>>=) [] _ = [] (>>=) (x:xs) f = f x ++ (xs >>= f) return :: a -> [a] return = (:[])

Following the bindings again we have

[[2,3],[4]] = (x:xs) => x = [2,3] ; xs = [[4]] (x:xs) >>= id = (id x) ++ (xs >>= id) = x ++ (xs >>= id) [[4]] = (y:ys) => y = [4] ; ys = [] (y:ys) >>= id = y ++ (ys >>= id) ys = [] => (ys >>= id) = [] => (y:ys) >>= id = [4] ++ [] = [4] => xs >>= id = [4] => (x:xs) >>= id = x ++ [4] = [2,3] ++ [4] = [2,3,4]

So all of this is to say that join actually does what one expects it to do on a list of lists. It joins them one by one into a single list.

The Associativity Law

The associativity law of a monad can be quite confusing, after all it takes the form:

(m >>= f) >>= g == m >>= ( x -> f x >>= g )

While not too complicated to understand it is difficult to see how it relates to a usual associativity law, which follows the form a * (b * c) = (a * b) * c. To recover the associativity the usual explanation is that one has to see it in terms of the monadic function composition (>=>) and while this is a valid way of doing so, I like to decompose things in terms of fmap, (>>=) and join.

So let's use what we did previously on the associativity law, starting on the left side, and replacing the atomic-looking type m with the dependent type M z:

(M z >>= f) >>= g = join (fmap f (M z)) >>= g = join (fmap g $ join ( fmap f (M z))) = join (fmap g $ join ( M (f z) )

and the right-hand side:

M z >>= ( x -> f x >>= g ) = M z >>= ( x -> join $ fmap g (f x)) = join $ fmap ( x -> join $ fmap g (f x)) (M z) = join $ M ( x -> join $ fmap g (f x)) z = join $ M (join $ fmap g (f z))

And essentially what it says is that if I have two functions f and g I can either do it in an orderly fashion where I apply them sequentially with join . fmap f followed by join . fmap g, or I can apply them both within the constructor and then join once within the constructor and one outside the constructor, and I should get the same thing. In fact if you replace f and g with id; this is the associativity law for monads as usually presented in a standard category theory textbook such as Mac Lane's Categories for the Working Mathematician (and recovering this was the whole point of this exercise in the first place).

HPR3027: What is quantum computing and why should we care?

Mar 10, 2020


What are quantum computers anyway?

Physical computing systems that take advantage of quantum effects.

What kind of quantum effects, and why does that matter?

Entanglement and superposition: Entanglement lets us do unusual, head-scratching kinds of things like teleportation. Superposition lets us harness the almost unimaginable potential of quantum mechanics to do things that conventional computers can never do.

How can you ever explain that in a podcast?

To really understand the details, you must have math, but math and audio formats are not so compatible. So I use analogies, and throw in some pithy quotes from Einstein and hope that does the trick.

Big picture?

Lots of work going on to build quantum processors (QPUs) that use quantum memory and, get this, will at some point actually do error correction. There are programming frameworks and rudimentary compilers to compile down python code all the way down to microwave pulses and laser pulses and there is control machinery to gather back the signals and interpret them to ones and zeros. Quantum computers will be securely networked using quantum protocols and we’ll all live happily ever after in a quantum computing world.

Questions? Please leave suggestions if you want to dive a bit deeper in some topic areas - it’ll encourage me to do more episodes.

HPR3026: Hex Bug and Battle Bots

Mar 9, 2020


Review/mods of fun Hex Bug and Battle Bots

HPR3025: Keep unwanted messages off the Fediverse

Mar 6, 2020

HPR3024: A funny thing happened the other day

Mar 5, 2020


Equipment used

Nexus 7 tablet

My faithful Dictaphone

Noise source
Noise source

HPR3023: Critique My Script, Episode 1 - Qots-Crew-Gen

Mar 4, 2020


This is my second HPR episode and the first in what could be a series about shell scripts I have written. This episode goes through a short script which randomly generates first and last names for a ten man aircrew to use with the Avalon Hill game B-17 Queen of the Skies.

You can see the basic script in action here:

and a more complicated version here, though based on the same underlying methodolgy:

Here’s the script:

#!/bin/sh first_names='./firstnames.txt' last_names='./surnames.txt' crew_positions='./positions.txt' crew_ranks='./ranks.txt' len_first_names=$(wc -l < ${first_names}) len_last_names=$(wc -l < ${last_names}) num_pairs=$(printf "10 ${len_first_names} ${len_last_names}" | \ awk 'BEGIN { srand() } { for (i=1; i<=$1; i++) { for(f = 2; f <= NF; f++) { num=int(rand() * $f + 1); printf num"," } printf "\n" } }') i=1 for crew_member in ${num_pairs} do line_num=$(printf "${crew_member}" | cut -d',' -f1) first_name=$(sed -n ${line_num}p ${first_names}) line_num=$(printf "${crew_member}" | cut -d',' -f2) last_name=$(sed -n ${line_num}p ${last_names}) crew_position=$(sed -n ${i}p ${crew_positions}) crew_rank=$(sed -n ${i}p ${crew_ranks}) # # Use the variables above to generate HTML. # Omitted here to simplify this example. # i=$((( ${i} +1 ))) done

HPR3022: FOSDEM 2020 Stand Interviews

Mar 3, 2020


Table of Contents Previously Interviewed Projects Projects we did not get to Interview (yet) 0 A.D. AdoptOpenJDK Apache Camel Checkmk Coderdojo Eclipse Foundation GitLab GNU Health Javascript Jenkins-x Kopano KubeVirt and Metal3 Micropython and Espruino Nuspell openHAB OpenStack Foundation OpenTAP OpenUK openWifi OWASP Percona PineTime PostGraphile Skolelinux / AlekSIS / Teckids Technoethical Tiny Go XCP-ng Zenroom Fenster Previously Interviewed Projects Apache Software Foundation Automotive Grade Linux CentOS CiviCRM Coreboot Debian Flashrom Foreman FreeBSD Project Free Software Foundation Europe Gentoo Linux GNOME Godot Engine Google Summer of Code (Saturday) Grafana Haiku (Saturday) illumos Infobooth on amateur radio (HAM Radio) Jenkins KDE LibreOffice Linux Professional Institute (Saturday) Matrix Mozilla Musescore (Saturday) Nextcloud OpenEmbedded OpenMandriva openSUSE Project oVirt OW2 Open Source Community Perl PostgreSQL ReactOS (Sunday) Software Freedom Conservancy (Sunday) The Fedora Project wolfSSL Projects we did not get to Interview (yet) 3Box (Sunday) Davx FOSSASIA (Sunday) Free Culture Podcasts (Sunday) Linphone LinuxBoot Mattermost Mautic (Saturday) MIT App Inventor (Sunday) ntopng (Sunday) ONLYOFFICE Open Source Design (Sunday) Open Source Test Management (Sunday) Pharo (Sunday) PINE64 (Sunday) Raku Sugar Labs (Saturday) Syndesis Tine 2.0 (Saturday) Tracim (Sunday) YottaDB 0 A.D.


0 A.D. is a free and open-source, real-time strategy game under development by Wildfire Games. It is a historical war and economy game focusing on the years between 500 BC and 1 BC for the first part, and a planned second part for the years 1 AD to 500 AD. The game is cross-platform, playable on Windows, macOS, FreeBSD, Linux, and OpenBSD. It aims to be entirely free and open-source, using the GPLv2+ license for the game engine and CC BY-SA for the game art. Wildfire Games is a global group of volunteer game developers. We create open source games and mods. Listen to the interview with Stanislas Dolcini from 0 A.D.


Links Project Website: https://play0ad.com Source Code: https://github.com/StanleySweet?tab=repositories Wikipedia: https://en.wikipedia.org/wiki/0_A.D._(video_game) https://wildfiregames.com/ AdoptOpenJDK


Prebuilt OpenJDK Binaries for Free!
Java™ is the world's leading programming language and platform. AdoptOpenJDK uses infrastructure, build and test scripts to produce prebuilt binaries from OpenJDK™ class libraries and a choice of either the OpenJDK HotSpot or Eclipse OpenJ9 VM. All AdoptOpenJDK binaries and scripts are open source licensed and available for free. Listen to the interview with Stewart X Addison AdoptOpenJDK


Links Project Website: https://adoptopenjdk.net/ Source Code: https://github.com/AdoptOpenJDK Wikipedia: https://en.wikipedia.org/wiki/OpenJDK#OpenJDK_builds Apache Camel


Apache Camel is an open source framework for message-oriented middleware with a rule-based routing and mediation engine that provides a Java object-based implementation of the Enterprise Integration Patterns using an application programming interface (or declarative Java domain-specific language) to configure routing and mediation rules. The domain-specific language means that Apache Camel can support type-safe smart completion of routing rules in an integrated development environment using regular Java code without large amounts of XML configuration files, though XML configuration inside Spring Framework is also supported. Camel is often used with Apache ServiceMix, Apache ActiveMQ and Apache CXF in service-oriented architecture projects. Listen to the interview with Rachel Yordán from Apache Camel


Links Project Website: https://camel.apache.org/ Source Code: https://github.com/apache/camel/ Wikipedia: https://en.wikipedia.org/wiki/Apache_Camel Checkmk


Best-in-class infrastructure and application monitoring. Helping you stay up and running from simple to the most complex environments. Listen to the interview with Marcel Arentz from Checkmk

Links Project Website: https://checkmk.com/ Source Code: https://github.com/tribe29/checkmk Wikipedia: https://en.wikipedia.org/wiki/Check_MK https://tribe29.com/ Coderdojo


CoderDojo organizes free coding workshops (called Dojo’s) for girls and boys from 7 to 18 years old. A Dojo is entirely prepared and led by volunteers. If you are older, then you can help out at an existing Dojo or start your very own CoderDojo! Listen to the interview with Coderdojo

Links Project Website: http://coderdojobelgium.be/en Wikipedia: https://en.wikipedia.org/wiki/CoderDojo Eclipse Foundation


The Eclipse Foundation provides our global community of individuals and organizations with a mature, scalable, and business-friendly environment for open source software collaboration and innovation. The Foundation is home to the Eclipse IDE, Jakarta EE, and over 350 open source projects, including runtimes, tools, and frameworks for a wide range of technology domains such as the Internet of Things, automotive, geospatial, systems engineering, and many others. Listen to the interview with Mikaël Barbero, Release Engineer, Eclipse Foundation


Links Project Website: https://www.eclipse.org/org/ Wikipedia: https://en.wikipedia.org/wiki/Eclipse_Foundation GitLab


GitLab is a web-based DevOps lifecycle tool that provides a Git-repository manager providing wiki, issue-tracking and CI/CD pipeline features, using an open-source license, developed by GitLab Inc. Listen to the interview with David Planella Director Of Community Relations at GitLab


Links Project Website: https://about.gitlab.com/ Wikipedia: https://en.wikipedia.org/wiki/GitLab GNU Health


GNU Health combines the socioeconomic determinants of health with state-of-the-art technology in bioinformatics and clinical genetics. It manages the internal processes of a health institution, such as financial management, stock and pharmacies or laboratories (LIMS) Listen to the interview with Axel K. Braun about GNU Health


Links Project Website: https://www.gnuhealth.org/ Source Code: https://savannah.gnu.org/projects/health Wikipedia: https://en.wikipedia.org/wiki/GNU_Health https://www.gnusolidario.org/ Javascript


Hackages is a community-based tech company with education at its core. We help you boost your skills and realise your projects through our expertise in training, product development, consultancy and community building. Listen to the interview with Marta Moliz about Javascript


Links Wikipedia: https://en.wikipedia.org/wiki/JavaScript https://hackages.io/ Jenkins-x


Jenkins X provides pipeline automation, built-in GitOps, and preview environments to help teams collaborate and accelerate their software delivery at any scale. Listen to the interview with Kara de la Marck, Open Source Community Manager at CloudBees, about Jenkins-x


Links Project Website: https://jenkins-x.io/ Source Code: https://github.com/jenkins-x Wikipedia: https://en.wikipedia.org/wiki/Jenkins_(software) Kopano


100% Open source collaboration tools: email, calendaring, Mattermost chat, webRTC video meetings, document collaboration with LibreOffice Online, integration with file storage services and more. Listen to the interview with Brian Joseph about Kopano


Links Project Website: https://kopano.io/ Source Code: https://stash.kopano.io/repos?visibility=public Wikipedia: https://en.wikipedia.org/wiki/Kopano_(software) KubeVirt and Metal3


Virtual Machine Management on Kubernetes. Building a virtualization API for Kubernetes. KubeVirt technology addresses the needs of development teams that have adopted or want to adopt Kubernetes but possess existing Virtual Machine-based workloads that cannot be easily containerized. More specifically, the technology provides a unified development platform where developers can build, modify, and deploy applications residing in both Application Containers as well as Virtual


There are a number of great open source tools for bare metal host provisioning, including Ironic. Metal3.io aims to build on these technologies to provide a Kubernetes native API for managing bare metal hosts via a provisioning stack that is also running on Kubernetes. We believe that Kubernetes Native Infrastructure, or managing your infrastructure just like your applications, is a powerful next step in the evolution of infrastructure management. Listen to the interview with KubeVirt and Metal3

Links Project Website: https://kubevirt.io/ Source Code: https://github.com/kubevirt Project Website: https://metal3.io/ Source Code: https://github.com/metal3-io/metal3-docs Micropython and Espruino


MicroPython is a lean and efficient implementation of the Python 3 programming language that includes a small subset of the Python standard library and is optimised to run on microcontrollers and in constrained environments.


Espruino is an open-source JavaScript interpreter for microcontrollers. It is designed for devices with small amounts of RAM (as low as 8kB). Espruino was created by Gordon Williams in 2012 as an attempt to make microcontroller development truly multiplatform. It was made open-source in 2013 after a successful Kickstarter campaign for a development board running the software. Listen to the interview with Christine Spindler from Micropython and Gordon Williams from Espruino


Links Project Website: https://micropython.org/ Source Code: https://github.com/micropython Wikipedia: https://en.wikipedia.org/wiki/MicroPython Project Website: https://www.espruino.com/ Source Code: https://github.com/espruino Wikipedia: https://en.wikipedia.org/wiki/Espruino Nuspell


Listen to the interview with Sander van Geloven from Nuspell


Links Project Website: https://nuspell.github.io Source Code: https://github.com/nuspell/nuspell http://hellebaard.nl openHAB


Empowering the smart home. A vendor and technology agnostic open source automation software for your home. Listen to the interview with Thomas Bail about openHAB

Links Project Website: https://www.openhab.org/ Source Code: https://github.com/openhab Wikipedia: https://en.wikipedia.org/wiki/OpenHAB OpenStack Foundation


The OpenStack Foundation promotes the global development, distribution and adoption of open infrastructure with more than 105,000 community members from 187 countries around the world. The OpenStack Foundation was founded in September 2012 to provide an independent home for the OpenStack cloud operating system, which has since become one of the largest and most diverse open source projects in history. Listen to the interview with Jeremy Stanley about OpenStack Foundation

Links Project Website: https://www.openstack.org/foundation/ Source Code: https://opendev.org/openstack Wikipedia: https://en.wikipedia.org/wiki/OpenStack OpenTAP


OpenTAP is an open source project for test automation. An open source test sequencing engine. The project is available online at http://Gitlab.com/OpenTAP/OpenTAP Listen to the interview with Michael Dieudonné about OpenTAP

Links Project Website: https://www.opentap.io/ Source Code: https://gitlab.com/OpenTAP/opentap OpenUK


We are a UK organisation committed to develop and sustain UK leadership in Open Technology. We promote businesses, projects and people, who use Open. We strive to collaborate across all existing organisations for Open. Listen to the interview with Amanda Brock about OpenUK


Links Project Website: https://openuk.uk https://openuk.uk/profiles/amanda-brock/ openWifi


openwifi: Linux mac80211 compatible full-stack IEEE802.11/Wi-Fi design based on SDR (Software Defined Radio). Listen to the interview with XianJun Jiao about openWifi


Links Source Code: https://github.com/open-sdr/openwifi OWASP


The Open Web Application Security Project (OWASP) is a nonprofit foundation that works to improve the security of software. Through community-led open source software projects, hundreds of local chapters worldwide, tens of thousands of members, and leading educational and training conferences, the OWASP Foundation is the source for developers and technologists to secure the web. Listen to the interview with Antonis Manaras about OWASP


Links Project Website: https://owasp.org/ Wikipedia: https://en.wikipedia.org/wiki/OWASP Percona


Percona is a leading provider of unbiased open source database solutions that allow organizations to easily, securely and affordably maintain business agility, minimize risks, and stay competitive. Listen to the interview with Evgeniy Patlan about Percona

Links Project Website: https://www.percona.com/ PineTime


An Open Source Smartwatch For Your Favorite Devices. Low Cost, High Fidelity.
The PineTime is a free and open source smartwatch capable of running custom-built open operating systems. Some of the notable features include a heart rate monitor, a week-long battery as well as a capacitive touch IPS display that is legible in direct sunlight. It is a fully community driven side-project, which means that it will ultimately be up to the developers and end-users to determine when they deem the PineTime ready to ship. Listen to the interview with Koen Zandberg about PineTime


Links Project Website: https://www.pine64.org/pinetime/ Source Code: https://github.com/bergzand Wikipedia: https://en.wikipedia.org/wiki/Pine_Microsystems PostGraphile


Extensible high-performance automatic GraphQL API for PostgreSQL Listen to the interview with Benjie Gillam, OSS Maintainer PostGraphile


Links Project Website: https://www.graphile.org/ Source Code: https://github.com/graphile Skolelinux / AlekSIS / Teckids


At Teckids, all children and adolescents become part of the Free Software community - as users and contributors. Our young tutors aged between 9 and 16 regularly work together on their workshops, which they then lead for children and adolescents of the same age. Listen to the interview with Niels Bradek from Skolelinux / AlekSIS / Teckids

Links Project Website: https://www.teckids.org/en/ https://wiki.debian.org/DebianEdu/ Technoethical


Technoethical is an online shop that sells hardware compatible with operating systems that fully respect users' freedom as defined by the GNU Project. We are based in Bucharest, Romania (European Union) and we ship worldwide. Listen to the interview with Tiberiu Turbureanu about Technoethical

Links Project Website: https://tehnoetic.com/ Tiny Go


TinyGo is a project to bring the Go programming language to microcontrollers and modern web browsers by creating a new compiler based on LLVM. You can compile and run TinyGo programs on several different microcontroller boards such as the BBC micro:bit and the Arduino Uno. TinyGo can also be used to produce WebAssembly (WASM) code which is very compact in size. Listen to the interview with Ron "Dead Program" Evans about Tiny Go

Links Project Website: https://tinygo.org/ Source Code: https://github.com/tinygo-org/tinygo Wikipedia: https://en.wikipedia.org/wiki/Go_(programming_language) https://hybridgroup.com/ XCP-ng


Turnkey Open Source Hypervisor. Based on XenServer, XCP-ng is the result of massive cooperation between individuals and companies, to deliver a product without limits. No restrictions on features and every bit available on GitHub! Listen to the interview with Olivier Lambert about XCP-ng


Links Project Website: https://xcp-ng.org/ Source Code: https://github.com/xcp-ng Wikipedia: https://en.wikipedia.org/wiki/Hypervisor Zenroom


Zenroom: easy cryptography to the people. Zenroom is a tiny and portable virtual machine that authenticates and manages access to data using human-readable smart contracts. Zenroom is easy to program to performs fast cryptographic operations for end-to-end encryption and runs on: desktop, embedded, mobile phones, clouds and web browsers. Listen to the interview with Denis "Jaromil" Roio from Zenroom


Links Project Website: https://zenroom.org/ Source Code: https://github.com/DECODEproject/zenroom/ https://dyne.org Fenster Fenster - Free Software Song

Links Wikipedia: https://en.wikipedia.org/wiki/Free_Software_Song Official: https://www.gnu.org/music/free-software-song.html Remix: http://freesoft.potlatch20.net/ RMS sings: https://www.youtube.com/watch?v=1BH7poMtPVU GNU: http://audio-video.gnu.org/audio Track name : Free Software Song Performer : Fenster Recorded date : 2002 Copyright : Copyright (C) 2002, Fenster LLC. Verbatim copying of this entire recording is permitted in any medium, provided this notice is preserved. Performers: Paul Robinson (vocals), Roman Kravec (guitar), Ed D'Angelo (bass), Dave Newman (drums), Brian Yarbrough (trumpet), Tony Moore (trumpet).

HPR3021: HPR Community News for February 2020

Mar 2, 2020


table td.shrink { white-space:nowrap } New hosts

Welcome to our new host:

Last Month's Shows Id Day Date Title Host 3001 Mon 2020-02-03 HPR Community News for January 2020 HPR Volunteers 3002 Tue 2020-02-04 World of Commodore 2019 Episode 8: Vote of thanks Paul Quirk 3003 Wed 2020-02-05 Hacker Public Radio 2019 2020 New Year Show Episode 4 Kevin Wisher 3004 Thu 2020-02-06 Fixing simple audio problems with Audacity Dave Morriss 3005 Fri 2020-02-07 Is ActivityPub Paving The Way to Web 3.0? Ahuka 3006 Mon 2020-02-10 Hijack Auxiliary Input of your car! operat0r 3007 Tue 2020-02-11 Photography 101 Paul Quirk 3008 Wed 2020-02-12 Hacker Public Radio 2019-20 New Year Show Episode 5 Kevin Wisher 3009 Thu 2020-02-13 Linux Inlaws S01 E01 monochromec 3010 Fri 2020-02-14 FOSDEM first impressions Andrew Conway 3011 Mon 2020-02-17 Linux is HARD rant with Intel graphics operat0r 3012 Tue 2020-02-18 Sample episode from Wikipediapodden Ken Fallon 3013 Wed 2020-02-19 Bash Tips - 21 Dave Morriss 3014 Thu 2020-02-20 A Headless Raspberry Pi Streaming Radio Jon Kulp 3015 Fri 2020-02-21 ActivityPub Conference 2019 - The Semantic Social Network Ahuka 3016 Mon 2020-02-24 Nixie tube clock and friends! operat0r 3017 Tue 2020-02-25 Developing Black and White Film Paul Quirk 3018 Wed 2020-02-26 Encrypted edit klaatu 3019 Thu 2020-02-27 Linux Inlaws S01E02 FOSDEM shenanigans monochromec 3020 Fri 2020-02-28 Validating data in Haskell tuturto Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 16 comments in total.

Past shows

There are 3 comments on 2 previous shows:

hpr2999 (2020-01-30) "SQRL - Secure Quick Reliable Login" by Daniel Persson. Comment 1: Ahuka on 2020-02-06: "Great show!"
hpr3000 (2020-01-31) "Chopin Free project" by Paul Quirk. Comment 2: Ahuka on 2020-02-02: "Great show!" Comment 3: mcnalu on 2020-02-02: "Great!"
This month's shows

There are 13 comments on 6 of this month's shows:

hpr3002 (2020-02-04) "World of Commodore 2019 Episode 8: Vote of thanks" by Paul Quirk. Comment 1: Windigo on 2020-02-18: "Thanks for the series"
hpr3003 (2020-02-05) "Hacker Public Radio 2019 2020 New Year Show Episode 4" by Kevin Wisher. Comment 1: folky on 2020-02-20: "Dark reader"
hpr3008 (2020-02-12) "Hacker Public Radio 2019-20 New Year Show Episode 5" by Kevin Wisher. Comment 1: norrist on 2020-02-26: "These 2 guys should get together more often"
hpr3009 (2020-02-13) "Linux Inlaws S01 E01" by monochromec. Comment 1: Ken Fallon on 2020-02-15: "Mailing list Discussion"Comment 2: Ken Fallon on 2020-02-15: "Murmer/Mumble"Comment 3: Peter Mortensen on 2020-02-19: "The predecessor?"Comment 4: Chris on 2020-02-19: "LinuxInlaws"
hpr3013 (2020-02-19) "Bash Tips - 21" by Dave Morriss. Comment 1: crvs on 2020-02-24: "So that's how you use shebangs!"Comment 2: Dave Morriss on 2020-02-24: "Writing awk scripts"
hpr3014 (2020-02-20) "A Headless Raspberry Pi Streaming Radio" by Jon Kulp. Comment 1: b-yeezi on 2020-02-20: "Trying this tonight"Comment 2: Jon Kulp on 2020-02-20: "Still Streaming with URL Update"Comment 3: b-yeezi on 2020-02-20: "Issue with mpg123"Comment 4: Jon Kulp on 2020-02-21: "HTTP not HTTPS"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2020-February/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Tags and Summaries

Thanks to the following contributors for sending in updates in the past month:
Claudio Miranda, Windigo, Dave Morriss

Over the period tags and/or summaries have been added to 16 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR3020: Validating data in Haskell

Feb 28, 2020



The space game I working on needs a admin interface that can by used by game masters to view and modify the simulation.

For start, I added interface for viewing, modifying and creating new people. It has three HTTP endpoints that are defined below. In this episode, I’ll concentrate on creating a new person and especially making sure that parameters used are valid.

/api/admin/people AdminApiPeopleR GET /api/admin/people/#PersonId AdminApiPersonR GET PUT /api/admin/addPerson AdminApiAddPersonR POST Types and parsing

There are two important approaches on making sure that data is valid. Making illegal state unpresentable and parsing instead of validation.

If it’s impossible to create invalid data, you don’t have to validate it. Instead of using Integer and checking that given parameter is 0 or more, you should use Natural. Since Natural can’t have negative values, you don’t have to validate it. Similarly, instead of using a list, you could use NonEmpty to make sure that there’s at least one element present in the collection.

Parse, don’t validate is similar approach. Instead of having a lax parser and then validating the result, parser should reject data that doesn’t make sense. By selecting suitable datatypes to represent data in the system, simply parsing incoming message is sometimes enough to validate it at the same time.

Person creation

Function in charge of generating a new person has signature of generatePersonM :: RandomGen g => StarDate -> PersonOptions -> Rand g Person. Given a current StarDate and PersonOptions describing what kind of person is needed, it will return a computation that can be executed to generate a random person.

PersonOptions is very barebones. There’s only one field to tell what kind of age the person should have and even that is an optional field.

data PersonOptions = PersonOptions { personOptionsAge :: Maybe AgeOptions } deriving (Show, Read, Eq)

AgeOptions has two possibilities. AgeBracket describes case where age should be inside of given range. ExactAge specifies exactly what age should be.

data AgeOptions = AgeBracket Age Age | ExactAge Age deriving (Show, Read, Eq)

Age is newtype wrapping Natural, thus Age can never be less than zero.

newtype Age = Age { unAge :: Natural } deriving (Show, Read, Eq, Num, Ord)

Hand written FromJSON instance takes care of rejecting numbers that aren’t integers and at least zero. One could skip the checks here and parsed Age still couldn’t be negative. Advantage of explicit checks is that we get much nicer error message instead of just annoying runtime exception.

instance FromJSON Age where parseJSON = withScientific "age" (\x -> case toBoundedInteger x of Nothing -> mempty Just n -> if n >= 0 then return $ Age $ fromIntegral (n :: Int) else mempty)

So, when creating a new person, you can have:

no age options at all, computer can pick something specific age, computer calculates date of birth based on current date age bracket, computer calculates date of birth based on current date and bracket age is always integer that is 0 or more

There’s still possibility of error. Nothing ensure that age bracket makes sense. It could be AgeBracket (Age 10) (Age 5) (bracket from 10 to 5). We need to add a bit of validation.

Data.Validation is “a data-type like Either but with an accumulating Applicative”. What this means to me is that I can validate multiple aspects and collect errors in a list. It’s handy for getting all the problems at once, instead of having to fix them one by one and retry after each fix.

Our validation function has signature validateAddPerson :: PersonOptions -> Validation [ErrorCode] PersonOptions. Given PersonOptions, it will give list of ErrorCode and original PersonOptions. Multiple validation functions can be combined for more complex validations.

In our example validateAgeOptions validates only age related options of the data. validateAddPerson is supposed to validate whole data, but currently it just delegates to validateAgeOptions. In the future, we can add more validations by adding more functions and chaining them with <* operator.

validateAddPerson :: PersonOptions -> Validation [ErrorCode] PersonOptions validateAddPerson opt = pure opt <* validateAgeOptions opt validateAgeOptions :: PersonOptions -> Validation [ErrorCode] PersonOptions validateAgeOptions opt = case personOptionsAge opt of Nothing -> _Success # opt Just (AgeBracket a b) -> if a <= b then _Success # opt else _Failure # [ AgeBracketStartIsGreaterThanEnd ] Just (ExactAge _) -> _Success # opt Putting it all together

Function that handles POST message and creates a new person is shown below:

postAdminApiAddPersonR :: Handler Value postAdminApiAddPersonR = do _ <- apiRequireAdmin msg <- requireJsonBody date <- runDB $ starDate _ <- raiseIfFailure $ validateAddPerson msg g <- liftIO newStdGen let person = evalRand (generatePersonM date msg) g pId <- runDB $ insert person returnJson (Entity pId person)

It does several things: - check that current user is admin - get json content and parse it to PersonOptions - get current star date from database - validate PersonOptions and return error if validation fails - get new random number generator - generate new person - insert it into database - return tuple of (PersonId, Person)


Types should represent only valid states. By having invalid state unpresentable, we can avoid many errors. Likewise, parsing should reject invalid data. This usually follows from having invalid states being unpresentable (you can’t parse invalid message to invalid data if you don’t have way to represent that invalid data).

Questions, comments and feedback welcome. Best way to reach me is either by email or in mastodon, where I’m tuturto@mastodon.social.

HPR3019: Linux Inlaws S01E02 FOSDEM shenanigans

Feb 27, 2020


Linux Inlaws - a podcast about on topics around free and open source software, any associated contraband, communism / the revolution in general and whatever else fancies your tickle.

Links: https://linuxinlaws.eu https://fosdem.org http://hackerpublicradio.org/eps.php?id=3009

HPR3018: Encrypted edit

Feb 26, 2020


Password-store and the pre command. Credit command

HPR3017: Developing Black and White Film

Feb 25, 2020


My photos will be available at: https://pquirk.com

HPR3016: Nixie tube clock and friends!

Feb 24, 2020


Nixie tube (English: /ˈnɪk. siː/ NIK-see), or cold cathode display, is an electronic device for displaying numerals or other information using glow discharge.


HPR3015: ActivityPub Conference 2019 - The Semantic Social Network

Feb 21, 2020

HPR3014: A Headless Raspberry Pi Streaming Radio

Feb 20, 2020


In this episode I talk about how I used a Raspberry Pi to create a streaming radio device to feed my pillow speaker. This is something I used to do with clock radios and later a satellite radio, but in an effort to decrease monthly subscription costs for services I did not use optimally, I discontinued my satellite radio subscription about a year ago. This new free solution is an excellent substitute for Satellite Radio so far, since I was mostly listening to this same channel on the Sat Radio but paying about $12 a month for the privilege. The device I’m using is a Raspberry Pi 2 Model B with Ubuntu Server. My barrier to this project in the past was not being able to find the URL for the stream I wanted but I discovered you can find it easily if you use Firefox with Video Download Helper to reveal the URL on a page with media playing (in this case it’s from TuneIn):


Strip off everything after the 48 to get raw URL:


Command to play stream with mpg123 on the Pi. Using the -q option to suppress output:

mpg123-pulse -q http://XX.XXX.XXX.XXX/radio-stationmp3-48 &

Once I figure out the command that plays the stream I want, I save the command as an executable script in /home/$user/bin.

Using the “Radio”

To start playing a stream you first have to SSH into the RasPi. This is easy from a laptop using any terminal emulator. I use pubkey auth so I don’t have to type a password every time. On my phone I use ConnectBot. Once I’m into the Pi I run the radio commands from CLI like espn or kmfa or krvs. To stop playback I kill the process with pkill mpg. I have a 3.5mm audio splitter Plugged into the headphone jack of the USB audio interface. In one side of the splitter I’ve got an old pair of earbuds where one side didn’t work, with the working earbud under my pillow. That’s my pillow speaker. On the other side of the splitter I put the audio cable for an FM transmitter, so that I can use an FM radio to listen to the stream while I’m walking around the house.

Click the image below to see pictures of the setup.

Raspberry Pi Radio

Links Raspberry Pi 2 Model B Ubuntu Server Video Download Helper (Firefox extension) The USB Audio interface I use Panda Wireless USB WiFi adapter mpg123 command-line audio player ConnectBot C. Crane FM Transmitter

HPR3013: Bash Tips - 21

Feb 19, 2020


The Environment (More collateral Bash tips) Overview

You will probably have seen references to The Environment in various contexts relating to shells, shell scripts, scripts in other languages and compiled programs.

In Unix and Unix-like operating systems an environment is maintained by the shell, and we will be looking at how Bash deals with this in this episode. When a script, program or subprocess is invoked it is given an array of strings called the environment. This is a list of name-value pairs, of the form name=value.

Using the environment

The environment is used to convey various pieces of information to the executing script or program. For example, two standard variables provided by the shell are 'HOME', which is set to the current user’s home directory and 'PWD, set to the current working directory. The shell user can set, change, remove and view environment variables for their own purposes as we will see in this episode. The Bash shell itself creates and in some cases manages environment variables.

The environment contains global data which is passed down to subprocesses (child processes) by copying. However, it is not possible for a subprocess to pass information back to the superior (parent) process.

Viewing the environment

You can view the environment in a number of ways.

From the command line the command printenv can do this (this is usually but not always a stand-alone command: it’s /usr/bin/printenv on my Debian system). We will look at this command later.

The command env without any arguments does the same thing as printenv without arguments. This is actually a tool to run a program in a modified environment which we will look at later. The environment printing capability can be regarded as more of a bonus feature.

Scripting languages like awk (as well as Python and Perl, to name just a few) can view and manipulate the environment.

Compiled languages such as C can do this too of course.

There are other commands that will show the environment, and we will look at some of these briefly.

Changing variables in the environment

The variables in the environment are not significantly different from the shell parameters we have seen throughout this Bash Tips series. The only difference is that they are marked for export to commands and sub-shells. You will often see variables (or parameters) in the environment referred to as environment variables. The Bash manual makes a distinction between ordinary parameters (variables) and environment variables, but many other sources are less precise about this in my experience.

The standard variables in the environment have upper-case names (HOME, SHELL, PWD, etc), but there is no reason why a variable you create should not be in lower or mixed case. In fact, the Bash manual suggests that you should avoid using all upper-case names so as not to clash with Bash’s variables.

Variables can be created and changed a number of ways.

They can be set up at login time (globally or locally) through various standard configuration files. It is intended to look at this subject in an upcoming episode so we will leave discussing the subject until then. By preceding the command or script invocation with name=value expressions which will temporarily place these variables into the environment for the command Using the export command Using the declare command with the -x option The value of an environment variable (once established) can be changed at any time in the sub-shell with a command like myvar=42, just as for a normal variable The export command can also be used to turn off the export marker on a variable Deletion is performed with the unset command (as seen earlier in the series)

We will look at all of these features in more detail later in the episode.

Long notes

I have provided detailed notes as usual for this episode, and these can be viewed here.

Links “GNU BASH Reference Manual” Section “3.7.3 Command Execution Environment” Section “3.7.4 Environment” GNU Coreutils Manual Section 23.2 env: Run a command in a modified environment

Wikipedia page on the env command

HPR series: Bash Scripting

Previous episodes under the heading Bash Tips:
Episode number HPR episode 1648 "Bash parameter manipulation" HPR episode 1843 "Some Bash tips" HPR episode 1884 "Some more Bash tips" HPR episode 1903 "Some further Bash tips" HPR episode 1951 "Some additional Bash tips" HPR episode 2045 "Some other Bash tips" HPR episode 2278 "Some supplementary Bash tips" HPR episode 2293 "More supplementary Bash tips" HPR episode 2639 "Some ancillary Bash tips - 9" HPR episode 2649 "More ancillary Bash tips - 10" HPR episode 2659 "Further ancillary Bash tips - 11" HPR episode 2669 "Additional ancillary Bash tips - 12" HPR episode 2679 "Extra ancillary Bash tips - 13" HPR episode 2689 "Bash Tips - 14 (Some auxiliary Bash tips)" HPR episode 2699 "Bash Tips - 15 (More auxiliary Bash tips)" HPR episode 2709 "Bash Tips - 16 (Further auxiliary Bash tips)" HPR episode 2719 "Bash Tips - 17 (Additional auxiliary Bash tips)" HPR episode 2729 "Bash Tips - 18 (Extra auxiliary Bash tips)" HPR episode 2739 "Bash Tips - 19 (Supplemental auxiliary Bash tips)" HPR episode 2756 "Bash Tips - 20 (Some collateral Bash tips)" Resources: Examples: bash21_ex1.sh bash21_ex2.sh bash21_ex3.awk bash21_ex4.sh bash21_ex5.sh bash21_ex6.sh bash21_ex6_1.cfg bash21_ex6_2.cfg

HPR3012: Sample episode from Wikipediapodden

Feb 18, 2020


Jan Ainali from the http://wikipediapodden.se/ podcast came over to the http://freeculturepodcasts.org/ booth at FOSDEM 2020.

They do a Swedish Language Podcast about wikipedia et al, and of course we added them to the http://freeculturepodcasts.org/ site. While their main shows are in Swedish, they also have summaries that they do in English which can be found at http://wikipediapodden.se/tag/english/, (RSS Feed).

HPR3011: Linux is HARD rant with Intel graphics

Feb 17, 2020


Help me help you! I rant about linux and Video drivers etc …

Get Video and CPU Info

# gives you info about video GPU in chrome! chrome://gpu

phoronix-test-suite system-info

# neat little project to dump out all kinds of info phoronix-test-suite system-info # get hard disk temperatures ! hddtemp /dev/sdb /dev/sdb: WDC WD4003FZEX-00Z4SA0: 37°C hddtemp /dev/sdc /dev/sdc: WDC WD4003FZEX-00Z4SA0: 36°C

vainfo - display information from VA API driver

lspci specific device

lspci -v -s 00:02.0 00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 630 (Desktop) (prog-if 00 [VGA controller]) Subsystem: ASRock Incorporation Device 3e92 Flags: bus master, fast devsel, latency 0, IRQ 126 Memory at a0000000 (64-bit, non-prefetchable) [size=16M] Memory at 90000000 (64-bit, prefetchable) [size=256M] I/O ports at 4000 [size=64] [virtual] Expansion ROM at 000c0000 [disabled] [size=128K] Capabilities: [40] Vendor Specific Information: Len=0c <?> Capabilities: [70] Express Root Complex Integrated Endpoint, MSI 00 Capabilities: [ac] MSI: Enable+ Count=1/1 Maskable- 64bit- Capabilities: [d0] Power Management version 2 Capabilities: [100] Process Address Space ID (PASID) Capabilities: [200] Address Translation Service (ATS) Capabilities: [300] Page Request Interface (PRI) Kernel driver in use: i915 Kernel modules: i915 lshw # lshw is a small tool to extract detailed information on the hardware configuration of the machine lshw -c video *-display description: VGA compatible controller product: UHD Graphics 630 (Desktop) vendor: Intel Corporation physical id: 2 bus info: pci@0000:00:02.0 version: 00 width: 64 bits clock: 33MHz capabilities: pciexpress msi pm vga_controller bus_master cap_list rom configuration: driver=i915 latency=0 resources: irq:126 memory:a0000000-a0ffffff memory:90000000-9fffffff ioport:4000(size=64) memory:c0000-dffff


The glxinfo program shows information about the OpenGL and GLX implementations running on a given X display.

glxinfo | egrep -i 'device|memory|OpenGL|direct'


dmesg | grep -e IOMMU -e DMAR dmesg | grep -E 'drm|radeon' | grep -iE 'firmware|microcode' dmesg | grep -i -e i915 -e drm -e vga

dmidecode - DMI table decoder

dmidecode -t baseboard | grep -i 'Product'

GPU usage

apt-get install intel-gpu-tools | intel_gpu_top

Google Dorks

when googleing try -ubuntu -xubuntu when searching for start up stuff use ‘systemd’ in your query

HPR3010: FOSDEM first impressions

Feb 14, 2020


FOSDEM is the biggest Free and Open Source conference in the world and on its 20th anniversary I decided to attend for the first time. By a good turn of fate, and some well-judged pitching, Ken Fallon secured a stand for the Free Culture Podcasts project which is an umbrella group that covers HPR, many of the shows on The Other Side Network and many more excellent podcasts that are released under creative commons licenses.

This audio is recorded in snippets in between manning the stand and gives some off-the-cuff observations from a FOSDEM noob. I was surprised to find that relatively few visitors to our stand had heard of HPR, which we quickly rectified of course, and I give a brief summary of the feedback we received. Also mentioned in this show, but not actually appearing, are my co-conspirators at FOSDEM, Ken, Beni, JWP as well as Dave Morriss who unfortunately wasn't able to join us in person but was very much there in spirit.

HPR3009: Linux Inlaws S01 E01

Feb 13, 2020


Linux Inlaws - a podcast about on topics around free and open source software, any associated contraband, communism / the revolution in general and whatever else fancies your tickle.

Please note that this and other episodes may contain strong language, offensive humor and other certainly not politically correct language - you have been warned (our parents insisted on this disclaimer - happy mum?). Thus the content is not suitable for consumption in the workplace (especially when played back on a speaker in an open plan office or similar environments), any minors under the age of 35 or any pets including fluffy little killer bunnies, your trusty guide dog (unless on speed) and cute t-rexes or other associated dinosaurs.

In this show the lads introduce themselves and discuss the technology they use and why they are putting on the show.

Links: https://linuxinlaws.eu/ email: feedback at linuxinlaws eu https://traceroute-online.com/mtr/

HPR3008: Hacker Public Radio 2019-20 New Year Show Episode 5

Feb 12, 2020


Hacker Public Radio 2019-20 New Year Show Episode 5

01:40 - 07:20 EST (09:40 - 12:20 UTC)

More war stories, podcasts, lawn mowing Timezones, Daylight Savings Time Antique computers - PDP, VAX, distro talk NAS discussion, EU politics Urugami joins Mongo joins Texas geography Motorcycles War stories NASA More war stories, podcasts, lawn mowing Timezones, Daylight Savings Time Antique computers - PDP, VAX, distro talk NAS discussion, EU politics

HPR3007: Photography 101

Feb 11, 2020

HPR3006: Hijack Auxiliary Input of your car!

Feb 10, 2020




Updated: Solved: The audio could use a dac or something nice but this will do. Not (DO NOT PLUG IN THE HARNESS WRONG ORDER OR YOU WILL BLOW AT LEAST 4 FUSES ) I had to swap out 3 in the passenger side and 1 for the rear lights on the IPDM E/R next to the battery in a #@$% spot.

pulled the pins and soldered a audio jack to them and fed it though the AC vent :

pin 1 - G : Satellite radio sound signal LH pin 2 + R : Satellite radio sound signal LH pin 3 - w : Satellite radio sound signal RH pin 4 + b : Satellite radio sound signal RH

Reference: https://www.myg37.com/forums/audio-v...ml#post4253485 https://rmccurdy.com/.scripts/downlo...5%20Q40/av.pdf pg 42

NOT SOLVED 08/21/2019 : So I'm sick of this jank setup .. the software is wonky and works about 1/2 the time .. I have to ƒ@#$ with it for about 5-10 min every time I want to use it … WIRELINQ is crap.. and I don't want the 600$ BT mod .. I just want AUX in !! I dont care if CD or SAT is spliced!

NO I'm not using a Apple device .. NO I'm not going BT because its crap audio .. NO I'm not using MONO or anything like that (discord) because that's even worse then BT… NO I'm not using a FM Transmitter because that's just stupid its a 2015 car it should have AUX input ..

maybe I can hack it myself the issue is that the SAT is in the @^ing trunk .. so I would have to find the wires that go to the trunk. I use a long speaker wire with alligator clips on it and a continuity tester (volt meter ) to hunt for it …

Part No
2591a 1ma5e

Model No

"11 12 Infiniti G25 G37 Radio CD Player 2591A-1MA5E Bulk 711"

SOLVED 01/20/2018 : YAY ! this works and I dont have to have grap BT audio

2015 INFINITI Q40 NONAV ANDROID IPOD WIRELINQ GROM-WLQ Electop 2 Pack USB 2.0 A Female to USB Micro Female Adapter Converter Wsken Mini2 Micro USB Magnetic LED Display Data Sync Fast Charge 3.28ft Cable for Android (Silver)

HPR3005: Is ActivityPub Paving The Way to Web 3.0?

Feb 7, 2020

HPR3004: Fixing simple audio problems with Audacity

Feb 6, 2020



I recorded the audio for the show I did with MrX in late 2019: 2972 “The_foot_of_the_ski_slope”. I was using my Zoom H2n recorder in my car, on a small tripod placed on the dashboard. Something about this setup caused the result to be very boomy and (to me) unpleasant to listen to. This episode is about what I did for a cure, after some research.

I have also been using the ‘Truncate Silence’ effect in Audacity incorrectly in the past, and I used the opportunity to learn how to do a better job with it.

Now, I am well aware that there are some skilled and experienced Audio Engineers out there in HPR-land. I am certainly not one of these, though I quite enjoy fiddling with audio to make it sound better. I’d like to make two requests:

If I didn’t do a good job, please tell me what I did wrong here, and how I should have done it. Think about doing a show (or shows) on HPR about how to deal with common audio problems. For example: how to remove a mains hum, the use of compression and normalisation. Long notes

A longer form of these notes may be found here (full_shownotes.html). These go into more detail on the steps I took to try and make the audio for show 2972 more tolerable.

Links Wikipedia page describing Audacity Audacity website Effects: Noise Reduction High-pass Filter Amplify Truncate Silence

HPR3003: Hacker Public Radio 2019 2020 New Year Show Episode 4

Feb 5, 2020


Hacker Public Radio 2019-20 New Year Show Episode 4

21:54 - 01:40 EST (02:54 - 06:40 UTC)

Chat about music, Star Wars, The Mandalorian Current main distro X2go RDP, Teamviewer, Dark Reader Firefox theme Pokey sucks at uRandom promotion Advent - https://en.wikipedia.org/wiki/Advent Pokey’s firestarters Thaj publicly shames Lyle  Lyle joins in shame Brief history of the New Year show  Thaj challenges everyone listening to find one HPR episode that doesn’t have tags and contribute them this year. Tags get sparse around episode 550 if you are trying to find a place to start. OH…and you also owe Ken a show too. Here are the instructions: https://hackerpublicradio.org/report_missing_tags.php Discussion about exercise  Pokey tries to help Mongo with Mumble  Thaj describes his custom keyboard layout  Pokey repairs his wife’s laptop Thaj publicly shames Klattu & Pokey for no tags on their shows CladioM explains the Latin tradition “Twelve Grapes”  Pokey talks about being a grandparent More HP & laptop talk Urugami joins Mongo joins Texas geography Motorcycles War stories NASA

HPR3002: World of Commodore 2019 Episode 8: Vote of thanks

Feb 4, 2020

HPR3001: HPR Community News for January 2020

Feb 3, 2020


table td.shrink { white-space:nowrap } New hosts

There were no new hosts this month.

Last Month's Shows Id Day Date Title Host 2978 Wed 2020-01-01 GARAGE DOOR operat0r 2979 Thu 2020-01-02 Bicycle Freewheel Maintenance Jon Kulp 2980 Fri 2020-01-03 FLOSS Weekly 553 - Hacker Public Radio Ken Fallon 2981 Mon 2020-01-06 HPR Community News for December 2019 HPR Volunteers 2982 Tue 2020-01-07 World of Commodore 2019 Episode 4: Bare metal c64 Emulation on Raspberry Pi Paul Quirk 2983 Wed 2020-01-08 my phone Jezra 2984 Thu 2020-01-09 RHEL 8 Workstation first looks JWP 2985 Fri 2020-01-10 Firefox Update Ahuka 2986 Mon 2020-01-13 Onlykey Updated operat0r 2987 Tue 2020-01-14 World of Commodore 2019 Episode 5: New games from Double Sided Games Paul Quirk 2988 Wed 2020-01-15 A tale of two hackers in the same system sigflup 2989 Thu 2020-01-16 Hacker Public Radio 2019-20 New Year Show Episode 1 Kevin Wisher 2990 Fri 2020-01-17 JDK14 - Wrap up edition Daniel Persson 2991 Mon 2020-01-20 Fix yer fog machine operat0r 2992 Tue 2020-01-21 World of Commodore 2019 Episode 6: Introduction to C64 OS Paul Quirk 2993 Wed 2020-01-22 Hacker Public Radio 2019-20 New Year Show Episode 2 Kevin Wisher 2994 Thu 2020-01-23 Wrestling As You Like It Episode 3 TheDUDE 2995 Fri 2020-01-24 ActivityPub Conference 2019 - ActivityPub: past, present, future Ahuka 2996 Mon 2020-01-27 Spideroak Update operat0r 2997 Tue 2020-01-28 World of Commodore 2019 Episode 7: Video Playback with 1541 Ultimate Paul Quirk 2998 Wed 2020-01-29 Hacker Public Radio 2019-20 New Year Show Episode 3 Kevin Wisher 2999 Thu 2020-01-30 SQRL - Secure Quick Reliable Login Daniel Persson 3000 Fri 2020-01-31 Chopin Free project Paul Quirk Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 9 comments in total.

Past shows

There is 1 comment on 1 previous show:

hpr95 (2008-05-12) "Security Wow!" by rowinggolfer. Comment 1: pokey on 2020-01-01: "A long overdue thank you."
This month's shows

There are 8 comments on 6 of this month's shows:

hpr2979 (2020-01-02) "Bicycle Freewheel Maintenance" by Jon Kulp. Comment 1: Dave on 2020-01-02: "Like the show"
hpr2988 (2020-01-15) "A tale of two hackers in the same system" by sigflup. Comment 1: ClaudioM on 2020-01-15: "Welcome Back!"Comment 2: Ken Fallon on 2020-01-20: "Condolences on behalf of HPR"
hpr2989 (2020-01-16) "Hacker Public Radio 2019-20 New Year Show Episode 1" by Kevin Wisher. Comment 1: beian on 2020-01-18: "silence?"Comment 2: brian on 2020-01-18: "oops"
hpr2991 (2020-01-20) "Fix yer fog machine" by operat0r. Comment 1: Ken on 2020-01-20: "Bigclive"
hpr2992 (2020-01-21) "World of Commodore 2019 Episode 6: Introduction to C64 OS" by Paul Quirk. Comment 1: Greg Nacu on 2020-01-29: "Thanks for the episode!"
hpr3000 (2020-01-31) "Chopin Free project" by Paul Quirk. Comment 1: ClaudioM on 2020-01-31: "Wow...just, WOW!"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2020-January/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Tags and Summaries

Thanks to the following contributors for sending in updates in the past month: Windigo, Dave Morriss

Over the period tags and/or summaries have been added to 9 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR3000: Chopin Free project

Jan 31, 2020


The Musopen (www.musopen.org) is a 501(c)(3) non-profit focused on improving access and exposure to music by creating free resources and educational materials. We provide recordings, sheet music, and textbooks to the public for free, without copyright restrictions. Put simply, our mission is to set music free.

Their latest Kickstarter aims to open the works of Frédéric Chopin copyright free.

HPR2999: SQRL - Secure Quick Reliable Login

Jan 30, 2020


In this podcast, we talk about what SQRL is, and how it works, why I feel that it’s an exciting new login method that is safe and easy to use.

SQRL Documentation

SQRL Forums

SQRL Github organization

Android Application

Github repository for Android Application

HPR2998: Hacker Public Radio 2019-20 New Year Show Episode 3

Jan 29, 2020


Hacker Public Radio 2019-20 New Year Show Episode 3

16:30 - 21:54 EST (21:30 - 02:54 UTC)

KWisher joins: ponders the New Year show editing New PC discussion, used PC acquisitions Remote desktop solutions Raspberry Pi IV DannW joins: text editors, Pascal, Fortran & other programming languages MS Windows licensing, software, operating systems More MS woes Asperger syndrome, some light political chat ClaudioM joins: talks about BSD Moss: Feren OS - https://ferenos.weebly.com/ ZFS discussion Urandom Podcast - https://urandom-podcast.info/ SELF - https://southeastlinuxfest.org/ Destination Linux Podcast - https://destinationlinux.org/ Mandriva, Sabayon, Slackware, Fedora discussion Softmaker Office, office suite discussion Pokey joins: automobiles, politics Mushrooms, farming, college HP EliteBooks Linux Mint, thermal paste Winter weather & driving, tire socks http://thermal-grizzly.com/en/products/16-kryonaut-en Netminer talks about his DOS days, ISO standards Spine/back issues, treatment Xoke joins in Pokey loves DuckDuckGo Gnome boxes virtualization - https://help.gnome.org/users/gnome-boxes/stable/ Android key mapper - https://f-droid.org/en/packages/io.github.sds100.keymapper/

HPR2997: World of Commodore 2019 Episode 7: Video Playback with 1541 Ultimate

Jan 28, 2020

HPR2996: Spideroak Update

Jan 27, 2020



service script:

# Make sure you have space or link the base path to some place else # make sure you have R/W for the plex user # ln -s /media/data/SPIDEROAK_CONFIG/ /home/plex/.config/SpiderOakONE [Unit] Description=SPIDEROAK STARTUP After=network.target [Service] User=plex Group=adm Type=simple ExecStart=/bin/bash -c ' PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin ; /usr/bin/SpiderOakONE --headless --verbose' [Install] WantedBy=multi-user.target

HPR2995: ActivityPub Conference 2019 - ActivityPub: past, present, future

Jan 24, 2020

HPR2994: Wrestling As You Like It Episode 3

Jan 23, 2020


In this episode I discuss what direction I’m taking the podcast in. Also more importantly I discuss what Supercards are and their purpose in Pro Wrestling.

HPR2993: Hacker Public Radio 2019-20 New Year Show Episode 2

Jan 22, 2020


Hacker Public Radio 2019-20 New Year Show Episode 2

11:00 - 16:30 EST (16:00 - 21:30 UTC)

TonyH & JoeB chat: ThinkPads, podcasts they are involved with KenF explains podcast download stats Commercial podcasts hurting the little guy? TonyH & JoeB chat: Headphones TonyH & Popey chat: Food, games, first computer experience Moss joins in Old data storage: cassette tapes, Zip & Jazz drives Thaj joins Moss & JoeB: Favorite books & authors Netminer discusses Autism Automobile inspections Netminer & TonyH chat: personal property boundary issues Handsome_pirate joins: steam engine chat HonkeyMagoo joins David Richards steam engine Youtube channel -https://www.youtube.com/channel/UCBdj-vOveiEFWe3vnGoJUag Mass transit, city traffic Corporate America philosophy Worker unions Fireworks Wimpy joins Ubuntu Mate discussion Donating used PC's https://8bitversus.com/ Timezone confusion?? Ubuntu podcast TonyH: how he discovered Linux

HPR2992: World of Commodore 2019 Episode 6: Introduction to C64 OS

Jan 21, 2020


Links of note:

https://www.tpug.ca/ https://pquirk.com/

HPR2991: Fix yer fog machine

Jan 20, 2020

HPR2989: Hacker Public Radio 2019-20 New Year Show Episode 1

Jan 16, 2020


Hacker Public Radio 2019-20 New Year Show Episode 1

04:30 - 11:00 EST (09:30 - 16:00 UTC)

Ken explains Sinterklaas https://en.wikipedia.org/wiki/Sinterklaas https://www.youtube.com/watch?v=vTGDFhi7z4U https://www.comptia.org/certifications/a Ken & Popey chat Netminer invites Popey & Ken's daughter to be guests on LinuxLUGcast Raspberry Pi IV discussion Popey and TonyH chat about restoring model cars Popey and TonyH chat about: More model cars, 8-bit computing, ZX Spectrum, Commodore https://8bitversus.com/ Sinclair calculator - https://en.wikipedia.org/wiki/List_of_Sinclair_calculators Popey and TonyH speak about Lenovo laptops Mr Cholmondley Warner (https://www.youtube.com/watch?v=tQWPR9TM0Gk) DaveM and TonyH talk more about model cars, their restoration and history DaveM is working on a "MagicMirror2" system on a Pi 3A+ to show status information Dinky Toys - https://en.wikipedia.org/wiki/Dinky_Toys

HPR2988: A tale of two hackers in the same system

Jan 15, 2020


Hi, I’m sigflup. This is about that awesome time I found that there was another hacker in the same system that I was hacking. Fun stuff

HPR2987: World of Commodore 2019 Episode 5: New games from Double Sided Games

Jan 14, 2020

HPR2986: Onlykey Updated

Jan 13, 2020


I chat about Onlykey updates along with plugins / updates / issues/ fixes


HPR2985: Firefox Update

Jan 10, 2020


Firefox has been the more secure alternative to Chrome, and it has over the last few months made some updates. So we may want to take a look and see if these are any good, and ask if they add to the security. In some cases there are valuable improvements, such as Facebook Container and the Monitor service.

Links: https://www.mozilla.org/en-US/firefox/flashback/ https://www.mozilla.org/en-US/firefox/privacy/ https://www.mozilla.org/en-US/privacy/firefox/ https://support.mozilla.org/en-US/kb/firefox-accounts-managing-account-data http://www.zwilnik.com/?page_id=1072

HPR2984: RHEL 8 Workstation first looks

Jan 9, 2020


Hi Everyone a bit random ideas about RHEL 8 on a low end laptop.

Interesting Git and flatpak are already installed out of the box.

MS Teams works great.

HPR2982: World of Commodore 2019 Episode 4: Bare metal c64 Emulation on Raspberry Pi

Jan 7, 2020

HPR2981: HPR Community News for December 2019

Jan 6, 2020


table td.shrink { white-space:nowrap } New hosts

Welcome to our new host:
Paul Quirk.

Last Month's Shows Id Day Date Title Host 2956 Mon 2019-12-02 HPR Community News for November 2019 HPR Volunteers 2957 Tue 2019-12-03 Lord D's Film Reviews: Ever lostnbronx 2958 Wed 2019-12-04 Haskell modules tuturto 2959 Thu 2019-12-05 Interview with Josh Clements about gpodder.net Ken Fallon 2960 Fri 2019-12-06 Dehydrated Foods Ahuka 2961 Mon 2019-12-09 Kubernetics / Cloud - Terminology Daniel Persson 2962 Tue 2019-12-10 Bespoke bike building Brian in Ohio 2963 Wed 2019-12-11 A walk through my PifaceCAD Python code – Part 3 MrX 2964 Thu 2019-12-12 Bolos and Bowties: Neckwear for Nerds Jon Kulp 2965 Fri 2019-12-13 instant feedback for students in maths beni 2966 Mon 2019-12-16 World of Commodore 2019 Episode 1: The Interviews Paul Quirk 2967 Tue 2019-12-17 Wrestling As You Like It Episode 2 TheDUDE 2968 Wed 2019-12-18 Life and Times of a Geek part 3 Dave Morriss 2969 Thu 2019-12-19 Crewing a spaceship in Haskell tuturto 2970 Fri 2019-12-20 The Fediverse Ahuka 2971 Mon 2019-12-23 World of Commodore 2019 Episode 2: Hacking GeckOS Paul Quirk 2972 Tue 2019-12-24 The foot of the ski slope Dave Morriss 2973 Wed 2019-12-25 Introduction to Advent of Code Daniel Persson 2974 Thu 2019-12-26 Guitar Setup pt. 2 NYbill 2975 Fri 2019-12-27 SimpleScreenRecorder and Vidcutter Ken Fallon 2976 Mon 2019-12-30 A walk through my PifaceCAD Python code – Part 4 MrX 2977 Tue 2019-12-31 World of Commodore 2019 Episode 3: Life after Commodore Paul Quirk Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 22 comments in total.

Past shows

There are 6 comments on 6 previous shows:

hpr2924 (2019-10-17) "Hacking an Alarm Clock to Make it Quieter" by Jon Kulp. Comment 1: Gabriel Evenfire on 2019-12-24: "Fun to listen to as always"
hpr2932 (2019-10-29) "Stardrifter RPG Playtest Part 10" by lostnbronx. Comment 1: Gabriel Evenfire on 2019-12-24: "Loved the series"
hpr2942 (2019-11-12) "Why I love lisps" by Nihilazo. Comment 4: Gabriel Evenfire on 2019-12-24: "Great first episode"
hpr2944 (2019-11-14) "ONICS Basics Part 4: Network Flows and Connections" by Gabriel Evenfire. Comment 2: Gabriel Evenfire on 2019-12-23: "Glad you liked it!"
hpr2947 (2019-11-19) "The Mimblewimble Protocol" by mightbemike. Comment 1: Gabriel Evenfire on 2019-12-24: "Enjoying this series"
hpr2955 (2019-11-29) "Machine Learning / Data Analysis Basics" by Daniel Persson. Comment 2: gerryk on 2019-12-06: "great! clear and informational"
This month's shows

There are 16 comments on 10 of this month's shows:

hpr2956 (2019-12-02) "HPR Community News for November 2019" by HPR Volunteers. Comment 1: jezra on 2019-12-10: "No more postcards?"
hpr2957 (2019-12-03) "Lord D's Film Reviews: Ever" by lostnbronx. Comment 1: Ken Fallon on 2019-12-03: "Great series but ..."Comment 2: lostnbronx on 2019-12-04: "Links"Comment 3: Ken Fallon on 2019-12-04: "Good point"
hpr2959 (2019-12-05) "Interview with Josh Clements about gpodder.net " by Ken Fallon. Comment 1: b-yeezi on 2019-12-05: "No problem. I'll do it"
hpr2962 (2019-12-10) "Bespoke bike building" by Brian in Ohio. Comment 1: petard on 2019-12-11: "I really enjoyed this"Comment 2: Jon Kulp on 2019-12-12: "Excellent progress"
hpr2963 (2019-12-11) "A walk through my PifaceCAD Python code – Part 3" by MrX. Comment 1: Gabriel Evenfire on 2019-12-24: "Great series"Comment 2: MrX on 2019-12-27: "Re: Great series"
hpr2964 (2019-12-12) "Bolos and Bowties: Neckwear for Nerds" by Jon Kulp. Comment 1: Ken Fallon on 2019-12-12: "Yes it is of interest to Hackers"Comment 2: Jon Kulp on 2019-12-12: "the model"
hpr2965 (2019-12-13) "instant feedback for students in maths" by beni. Comment 1: Dave Morriss on 2019-12-19: "Cool project!"
hpr2966 (2019-12-16) "World of Commodore 2019 Episode 1: The Interviews" by Paul Quirk. Comment 1: Jon Kulp on 2019-12-19: "Legacy Tech"Comment 2: Dave Morriss on 2019-12-19: "Great show!"
hpr2967 (2019-12-17) "Wrestling As You Like It Episode 2" by TheDUDE. Comment 1: BRonaldo on 2019-12-17: "WWE"
hpr2974 (2019-12-26) "Guitar Setup pt. 2" by NYbill. Comment 1: NYbill on 2019-12-26: "Heh, editing..."
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-December/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Tags and Summaries

There were no tag or summary updates in the past month.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2979: Bicycle Freewheel Maintenance

Jan 2, 2020


This is a short episode where I explain how to service your bicycle freewheel if it's misbehaving. My pedals were turning around when I walked the bike, and they ought to be stationary. A quick dose of chain oil in the freewheel fixed the problem. Click the image to see photos showing how to do this.

Bicycle Freewheel Lube


Jan 1, 2020


Are you afraid if your garage door ? Have no fear!

HPR2977: World of Commodore 2019 Episode 3: Life after Commodore

Dec 31, 2019

HPR2976: A walk through my PifaceCAD Python code – Part 4

Dec 30, 2019


This is the last show in the series. The series was recorded in one go and split into multiple parts. This last section is pretty short; it covers the main program section at the bottom of my script that calls all the other functions and allows the user to quit the program. In this episode I also mention explanatory notes that I included in my script. These are mainly for my own benefit so I could remember how I set up lirc. I’ve included these notes at the end of these show notes.

Main program
Turn LCD backlight on, print System up message to LCD, wait a few seconds then clear screen. Activate push buttons on control and display board. Activates various IR buttons waiting on input from the remote control. Print quit message to terminal, waiting for input, repeat message until q is entered by user. When q is entered deactivate buttons and turn LCD backlight off.

Below are my Lirc explanatory comments at the end of my Python script.

This is the Linux IR control program
LIRC (Linux Infrared remote control) is an open source package that allows users to receive and send infrared signals with a Linux-based computer system.

Tool used to record valid IR codes from your remote control. It generates the file /etc/lirc/lircd.conf, possibly overwrites original file so use with caution. It attempts to recognise your remote control from a series of button pushes. If the remote is not recognised then it captures the codes in raw mode, I abandoned this tool and got a valid IR file for a very similar remote control on the internet, see info below

File used to store IR codes for your remote control, either using the tool irrecord or from somewhere on the internet. This file is a direct copy of file "BN59-00861A-SAMSUNG-TV.conf" I added the Samsung TV string to the file name.

Tool used to get the key names for your particular remote control, for this to work you must first have a valid /etc/lirc/lircd.conf file

This file is used to store the remote control key names that you want to activate, and what action is to be taken when the button is pushed. Adding the field "remote =" allows the use of multiple remote controls. The remote control key names can be found by using the command "irw", I created a file called ~/scripts/remote-key-names-sorted.txt to store the valid key names for my Samsung remote control

List of valid remote control key names for my Samsung remote control, this was generated using the irw command. I used the "tee" command to pipe output to the screen and write output to this file at the same time, see file for further details of commands I used.

HPR2975: SimpleScreenRecorder and Vidcutter

Dec 27, 2019


In today’s show Ken talks about two small applications to make recording and trimming video easy.

What is SimpleScreenRecorder?

SimpleScreenRecorder is a Linux program that I’ve created to record programs and games. There were already a few programs that could do this, but I wasn’t 100% happy with any of them, so I created my own.

My original goal was to create a program that was just really simple to use, but as I was writing it I started adding more and more features, and the result is actually a pretty powerful program. It’s ‘simple’ in the sense that it’s easier to use than ffmpeg/avconv or VLC, because it has a straightforward user interface.

What is VidCutter

The simplest & sexiest tool for cutting and joining your videos without the need for re-encoding or a diploma in multimedia. VidCutter focuses on getting the job done using tried and true tech in its arsenal via mpv and FFmpeg.

Links SimpleScreenRecorder Homepage vidcutter Homepage VidCutter – Linux Video Cutting Or Trimming App review on Linux And Ubuntu

HPR2974: Guitar Setup pt. 2

Dec 26, 2019


Heh, listen to NYbill tune a guitar for an hour.

Part two of guitar set up. Fret polishing, neck relief, string height, and intonation.


Stewart MacDonald:


Allied Lutherie:

Guitar Fetish:

Zona micro fiber polishing paper:

Pics for the episode:

HPR2973: Introduction to Advent of Code

Dec 25, 2019


I discuss all the challenges we have seen so far during the Advent of Code and talk about what they entailed and how hard they were to solve.

HPR2972: The foot of the ski slope

Dec 24, 2019


Another in the chat series from Edinburgh Hosted by MrX and Dave Morriss

This time we met up for breakfast on Sunday 24th November in a pub/restaurant in an area called Hillend, just outside Edinburgh in Midlothian. The hill close by is the location of the Midlothian Snowsports Centre, an artificial Ski Slope which is very popular in the region for recreation and training.

We chatted for a while inside then moved to Studio C in the car park and recorded this episode.

PDAs and the like

We were talking about PDAs (Personal Data Assistants) from the 1980’s.

MrX had recently been offered a Gemini device and had at one time owned a Psion Series 3c. Dave owns a broken Psion Series 5 (and recently parted with a working one after much bargaining). Dave struggled to remember devices like the Palm Pilot which were quite popular in the 80’s and 90’s. These had no keyboard, but offered a touch-sensitive screen, used with a stylus, and had handwriting recognition1. MrX mentioned the Compaq iPAQ PDA (Compaq was later acquired by Hewlett Packard) from the 2000’s, which was a much advanced PDA with similar features. Software annoyances Mr X has had some problems with the latest Audacity on Ubuntu. It sometimes does not launch from the menu link after an upgrade. Calibre on Dave’s Debian Testing system has stopped working recently, due to a Python error.2 Dave uses Clementine, the music player, which turns off the UI when you close it down the wrong way and apparently doesn’t provide a way to enable it again without hacking the configuration file3. MrX had problems with audio device recognition and uses hdajackretask to correct this. This is part of the alsa-tools-gui package on Debian (and related)4, but has a non-intuitive UI. OS choices Dave uses Raspbian Lite on his headless Raspberry Pis (which he secures using advice from Ken Fallon’s HPR show on preparing the Raspbian image). MrX uses standard Raspian on RPis, Ubuntu as his main Linux version, as well as OSMC (Open Source Media Center) on a Raspberry Pi, for watching media. Dave originally started with Fedora (actually Red Hat version 4 for a brief time) then moved to Ubuntu (Kubuntu) before moving to Debian Testing on his desktop, and KDE Neon on his laptop. Both had used Crunchbang at one point, another Debian-based distribution. A few other topics MrX uses a Wiki service (https://www.wikidot.com/). Dave uses MediaWiki on a Raspberry Pi and has scripts that update some of the contents (mainly tables). There was discussion about using Pandoc (https://pandoc.org/) to generate MediaWiki markup from something like Markdown. Emulating a Bash session in a web browser. One example is: http://bellard.org/jslinux/ Online Python tools. For example: https://repl.it/languages/python3 Midnight Commander (https://midnight-commander.org/) contains its own editor. Notepadqq (https://notepadqq.com/) is a Notepad++-like editor for the Linux desktop. File managers: MrX has problems with the Ubuntu file manager; he uses Nemo (https://en.wikipedia.org/wiki/Nemo_(file_manager)) for its more advanced features Dave uses KDE’s Dolphin (https://en.wikipedia.org/wiki/Dolphin_(file_manager)) Links Location: Hillend (Wikipedia) Midlothian (Wikipedia) Midlothian Snowsports Centre (Wikipedia) PDAs (Personal Data Assistants - Wikipedia page) Psion Organiser II (Wikipedia) Psion Series 3 (Wikipedia) Psion Series 5 (Wikipedia) Palm Pilot (Wikipedia) Gemini PDA (Wikipedia) Compaq/HP iPAQ PDA (Wikipedia) Compaq computers iPAQ Software niggles: Audacity software Calibre e-book Manager Clementine music player hdajackretask from the ALSA Project Operating system choices: Raspbian Lite Dave’s HPR show about his what_pi script Open Source Media Center (OSMC) Crunchbang Linux (Wikipedia) MrX’s shows that we were talking about: Describing how I listen to podcasts PART 1 Describing how I listen to podcasts PART 2 Describing how I listen to podcasts PART 3 Describing how I listen to podcasts PART 4 Describing how I listen to podcasts PART 5 A walk through my PifaceCAD Python code – Part 1 A walk through my PifaceCAD Python code – Part 2 The previous episode: Two HPR hosts living in the same region finally meet up!

The person using a Palm Pilot to take meeting notes had an external keyboard, and wasn’t using handwriting recognition!↩

calibre was failing with the error: ImportError: No module named functools_lru_cache. It later proved possible to fix this by reinstalling a Python module: pip2 install --force backports.functools_lru_cache↩

There have been no releases of Clementine since 2016 sadly, though there are more recent changes on the GitHub page.↩

Information on the web about alsa-tools-gui seems a little sparse. The hdajackretask application has a README file in the distribution that gives some information.↩

HPR2971: World of Commodore 2019 Episode 2: Hacking GeckOS

Dec 23, 2019

HPR2969: Crewing a spaceship in Haskell

Dec 19, 2019



Every spaceship in game needs a crew to operate it. Smaller ships with fewer components require less crew than huge ones with lots of components.


Unit stats lists amount of crew required to operate a spaceship and if they need sleeping quarters.

data UnitStats = UnitStats { unitStatsMinimumCrew :: ![CrewRequirement] , unitStatsNominalCrew :: ![CrewRequirement] , unitStatsCrewSpace :: !TotalCrewSpace , unitStatsCrewSpaceRequired :: !CrewSpaceReq } deriving (Show, Read, Eq)

Different positions a crew can have is an enumeration:

data CrewPosition = Commander | Navigator | Signaler | SensorOperator | Gunner | Doctor | Nurse | Driver | Helmsman | Artificer | Crew | Passenger deriving (Show, Read, Eq, Enum, Bounded) derivePersistField "CrewPosition"

Rank of a crew member isn’t a military rank, but rather their position in ship’s internal hierarchy:

data CrewRank = SecondClass | FirstClass | Senior | Chief deriving (Show, Read, Eq, Enum, Bounded) derivePersistField "CrewRank"

Amount of crew is newtype that helps me not to mix different types of numbers with each other.

newtype CrewAmount = CrewAmount { unCrewAmount :: Int } deriving (Show, Read, Eq, Ord, Num)

Total crew space of a ship is divided to three different types: steerage, standard and luxury.

data TotalCrewSpace = TotalCrewSpace { totalCrewSpaceSteerage :: !(CrewSpace SteerageQuarters) , totalCrewSpaceStandard :: !(CrewSpace StandardQuarters) , totalCrewSpaceLuxury :: !(CrewSpace LuxuryQuarters) } deriving (Show, Read, Eq)

Again, crew space is newtype so I don’t mix different types of numbers with each other.

data CrewSpace a = CrewSpace { unCrewSpace :: CrewAmount } deriving (Show, Read, Eq)

I could have modeled fact that vehicle might need crew space with Bool, but having a descriptive name and type is more to my liking.

data CrewSpaceReq = CrewSpaceRequired | CrewSpaceOptional deriving (Show, Read, Eq) derivePersistField "CrewSpaceReq"

The fact that single person could manage multiple components is reflected by ComponentCrewReq having Double instead of Integer

-- | Crew requirements for a component data ComponentCrewReq = ComponentCrewReq CrewPosition Double deriving (Show, Read, Eq) In closing

If you have questions, comments or feedback, easiest way to catch me nowdays is by email or in fediverse where I’m tuturto@mastodon.social

HPR2968: Life and Times of a Geek part 3

Dec 18, 2019



In the last part of my story (show 1811 in 2015) I told you about some of my experiences at the University of Manchester as a postgraduate student from around 1973.

Today I want to talk a little more about my time in Manchester and mention some of the things I did that may be of interest to Hackers!

Researching for the episode

As I have been researching for this HPR episode I realise how long ago some of these events were - in Internet years particularly. In many cases I could find no online records of places, equipment or people. This seems to be because any records there might be are on paper and have never made it online. I contacted a company that made some of the laboratory equipment I used that I thought might be of interest, and the person I contacted said that although he remembered what I was referring to the company had kept no records of it and had had to discontinue it due to modern safety concerns.

I find this somewhat dispiriting and it makes me feel very very old!

Long notes

I have provided detailed notes as usual for this episode. The HTML version can be viewed here and the ePub version downloaded from here.

Links Building experimental apparatus: Wikipedia page for Dexion - for building metal structures Wikipedia page on the “Skinner Box” or Operant Conditioning ChamberHandy Tube” used for making Skinner Boxes Video tape recorders: The Rewind Museum reel-to-reel video recorders Wikipedia page on Video tape recorders Youtube video about a Sanyo Reel to Reel Video Tape Recorder Logic programming: Wikipedia page on the Logic Gate Wikipedia page on the (electronic) “Flip-Flop” D-MAC Digitiser: StackExchange article discussing the D-MAC digitiser ICT (ICL) computers: Wikipedia page on the ICT (ICL) 1900 series Wikipedia page on the ICL GEORGE operating system Teleprinter: Wikipedia page on the Teletype Model 33 CDC computers: Wikipedia page on the CDC Cyber range Wikipedia page on the APL language Sinclair calculators: Wikipedia page on the Sinclair Scientific New Scientist advertisement December 1975 Sinclair Scientific operating instructions [This link might be dead; try the archive.org one below] https://web.archive.org/web/20141021211903/http://phils.bitboxes.co.uk/scan_and_ocr/manuals/sinclair_scientific/ Sinclair Scientific simulator Vintage Calculators Reverse Polish Notation Previous episodes: Life and Times of a Geek part 1 (2014-12-18) Life and Times of a Geek part 2 (2015-07-13) Resources: Full show notes ePub show notes

HPR2967: Wrestling As You Like It Episode 2

Dec 17, 2019


Today’s episode is about the landscape of professional wrestling today, the hierarchy, and how it came to be that way, and a brief explanation of different styles of professional wrestling.

HPR2966: World of Commodore 2019 Episode 1: The Interviews

Dec 16, 2019


Hello, good people of Hacker Public Radio, my name is Paul Quirk and this is my very first ever podcast. I would like to give credit Klaatu of Gnu World Order for making me aware of Hacker Public Radio, which I’ve been a listener of for the past year. As we near the holiday season of the winter solstice, I decided to give back to the open source community with this gift of a mini series of podcasts about the World of Commodore from December 7, 2019.

The World of Commodore is an annual computer expo dedicated to Commodore computers that is normally held on the first Saturday of December in the city of Mississauga, Ontario. It started off back in 1983 by Commodore Canada as a trade show where Commodore and related vendors could showcase their latest products for the holiday season. As a Commodore computer nerd kid of the 1980’s living within an hour’s drive of Mississauga, this was an event I always looked forward to with excitement. For me, this was bigger and better than Santa Claus. Commodore went bankrupt in 1994, but a decade later, the show was revived by the Toronto PET user’s group, or TPUG, one of the world’s oldest computer user groups of which I am a member. Today’s World of Commodore is very different from the expo’s of the 1980’s, and has transformed into an event where hackers from around the world gather together to share ideas and show off their own discoveries and products, both open source and commercial.

Since many listeners and contributors of Hacker Public Radio got started with a Commodore computer at some time, and since this event has grown beyond Commodore products and into open source hardware and software, I thought this event would be of great interest to this community, and it is my hope that many of you listeners might join us at next year’s World of Commodore.

I have decided to create a miniseries of podcasts of this event which I will release on a weekly schedule. In this first episode, I walk around the trade show floor and interview various exhibitors, vendors, and members of TPUG. As there is a visual element to this podcast, I have posted pictures of the exhibits in my personal non-commercial blog at pquirk.com, which I encourage you to visit in order to get the full experience. And so, with no further ado, let’s all go to the wonderful world of Commodore.

https://www.tpug.ca/ https://signalsfromspace.ca/ https://doublesidedgames.com/ https://pquirk.com/2019/12/08/world-of-commodore-2019-episode-1/

HPR2965: instant feedback for students in maths

Dec 13, 2019


I'm trying to make sure that this show doesn't come across as as advertisment placement on HPR I won't provide a link to our application (which wouldn't help a lot anyway as we don't really have much of a web site anyway.).

However I'll link to some of the technical components:

The Computer Algebra System we use is called Maxima, its history goes back to the early 80s. It's written in common lisp.

We have considered switching to SymPy as a more modern alternative. SymPy doesn't offer the feature completeness Maxima does, though. It has still a long way to go.

Our servers run Debian. The current version is written in PHP but we are working on a new version based on dockerized Django with a JS frontend in Ember along with some micro services written in Go, Python and PHP.

To render math we use MathJax in the current version and KaTeX in the new version. The PDF-export of worksheets is of course done in LaTeX.

HPR2964: Bolos and Bowties: Neckwear for Nerds

Dec 12, 2019


It's probably because of a non-conformist streak in me, but I've never liked traditional neckties. In fact I never wanted to wear any ties until I got my first bolo tie, which was sufficiently different from everyone else and easy enough to put on that I decided I could wear bolo ties. I've built a collection of about a dozen of these and they always get positive comments, especially the ones made from recycled circuit boards. Recently I've expanded my horizons to include bowties, which have a more formal appearance and the added nerd factor of being difficult to tie for most people. In this episode I talk about my ties.

Click image to view photo gallery

Bolos and Bowties

Links Circuit Breaker Labs upcycled Jewelry made from circuit boards. 10 Reasons to Wear a Bowtie

HPR2963: A walk through my PifaceCAD Python code – Part 3

Dec 11, 2019



The script being discussed in this show is available for download with the previous show: cad-menu.py


def button0(event):
Play / Pause Button
Print message to lcd and toggle between play and pause for podcasts, then runs init_display to display available options

def button1(event):
Track Information button
Print message to lcd then display current moc track information such as moc state, current time, time left, current playlist number of total playlist number & podcast title.

Example output from command mocp --info

State: PAUSE File: /home/pi/files/mp3/hpr1597.mp3 Title: Steve Smethurst - HPR1597: Extravehicular Activity (Hacker Public Radio) Artist: Steve Smethurst SongTitle: HPR1597: Extravehicular Activity Album: Hacker Public Radio TotalTime: 14:11 TimeLeft: 02:47 TotalSec: 851 CurrentTime: 11:24 CurrentSec: 684 Bitrate: 64kbps AvgBitrate: 64kbps Rate: 44kHz

def button2(event):
Previous Track Button
Button is only active if button is pushed twice within 0.3 seconds. This was added to stop moving to a new track by accidental pushing of button. If menu = 0 or 1 and value of variable TimeDiff is less than 0.3 then Print message to lcd and move to previous track in playlist. If menu = 2 and button pressed twice within 0.3 then display number of HPR shows in the queue

def button3(event):
Next track Button
Button is only active if button is pushed twice within 0.3 seconds. This was added to stop moving to a new track by accidental pushing of button. If menu = 0 or 1 and value of variable TimeDiff is less than 0.3 then Print message to lcd and move to next track in playlist Button currently has no function if menu = 2

def button4(event):
Toggle backlight Button
If 1st time button is pushed then turn off blinkstick and display main menu else Toggle lcd backlight between on and off

def moc_seek():
Used to seek backward or forward in track being played in mocp SeekPosition is a global variable used to store the current seek position, its value changes up and down when using button6 and button7

def button5(event):
Jogg switch
This button is selected by momentarily pushing in the left/right toggle button. Button located on the top of unit
If menu equals 0 or 1, [PODCASTS or AUDIOBOOKS] menu then
if not in seek menu then display seek menu if in seek menu then jump forward or back in track by the amount currently displayed on the seek menu, uses function moc_seek() If menu equals 2, [SYSTEM] menu then Get date and time information, Clear screen, turn on LCD backlight print the shutdown message with date and time info to lcd & then issue the shutdown command def button6(event):
Left Jogg switch decrement through menus also used during seek
This button is selected by momentarily pushing the toggle switch to the left. Button located on the top of unit
Button only active if more than 0.3 seconds has passed since it was last pushed, this was added to get around switch bounce causing multiple jumps in menu, think left and right jogg switch is a bit noisy. If in seek menu SeekPosition decrements by one until SeekMin is reached, and then returns to 0 each time the display is updated with the decremented value stored in dictionary SeekDisplay If not in seek menu Menu decrements down by one until MenuMin is reached then rolls over to MenuMax

def button7(event):
Same as button6 above but instead increments value, i.e. menu or seek value is incremented by 1

def print_ir_code(event):
Used during debugging to get remote control working, came from piface examples page, prints IR code print(event.ir_code)

def ir_play(event):
If the play button is pushed on the remote control twice within 0.5 seconds and if IR is active then toggle backlight and toggle between play and pause

def ir_info(event):
If the info button (pause) is pushed on the remote control twice within 0.5 seconds and if IR is active then toggle backlight and display on the LCD information about the current track

def ir_rewind(event):
If the rewind button is pushed on the remote control and if IR is active then toggle backlight and go to previous track on playlist

def ir_forward(event):
If the forward button is pushed on the remote control and if IR is active then toggle backlight and go to next track on playlist

def ir_stop(event):
If the stop button is pushed on the remote control and if IR is active then toggle backlight

def ir_blue(event):
Activate and deactivate IR buttons on the remote control, turns blinkstick on red when IR active. When blue button is pushed twice within 0.5 seconds on remote control, toggle backlight and display momentary message on LCD display giving IR status i.e. are the remote control buttons active or deactive.

All remote buttons bar this one are affected. This feature was added to remotely disable all the buttons while using the TV remote control media buttons these would sometimes falsely trigger things

The double push of the blue button within 0.5 seconds was added as sometimes a single push of it was required on my TV and this would falsely activate it

Feature added to check if var FirstPass is set to true, i.e. backlight button4 has not pushed since boot

button4 normally toggles backlight but turns off hpr queue LED first time it’s pushed after boot.

HPR2962: Bespoke bike building

Dec 10, 2019


Links hpr 1282 john kulps efforts hpr 2869 part one of my build hpr 2875 part two recycled recumbent
https://sites.google.com/site/recycledrecumbents/home fish mouth cutting on recumbents.com
http://www.wisil.recumbents.com/wisil/Plans/frametubes.htm Pictures

(The images below may be clicked to view the full-sized versions)

Mocking up parts
mocking up parts to see spacing, especially the crankset

Laying out fishmouths
laying out ‘fishmouth’ cut, used to connect two tubes

Cutting fishmouths
lay out fishmouth

Cutting fishmouths
another layout picture, note marks on tube

Cutting fishmouths
finished product

Cutting fishmouths
test fitting assembly one, the engine room

Brazing complete
brazing complete! assembly one done

Readying assembly
setting up assembly tube, gray tube slips inside the red tube

Removing tab
need to cut that small tab off, get to hear this in the recording

Jigging up
jigging up the frame, similar to john kulps set up, see hpr 1282

Still in the jig
still in the jig but all brazed up, top half of frame done!

More brazing to do
the next part will be modifiying the rear triangle and brazing it where i’m pointing to.

Summary all in all, went better than expected, i’ll clean up those brazing joints after the bike is done and has been ridden for a while, before I paint it. brazing isn’t as difficult as i thought it might be. give it a try its a cool hacker skill!

HPR2961: Kubernetics / Cloud - Terminology

Dec 9, 2019


We talk about terms often used when using Kubernetes.

Terms we talk about

Node - Machine to run jobs on. Cluster - Grouping of nodes to deploy work to. Container - Compute unit that we can run in the cloud Pod - One or more containers that are one unit in the cloud that could be started, stopped, or restarted. Service - Different network services that serve the pods Load balancers - Balance network calls to different pods Certmanager - Handles certificates, for instance, let’s encrypt. Ingress - Handles traffic from the external network Volumes - External resources used by pods to keep state ConfigMap - Configuration parameters that could be changed without restarting the pods or deployment. Deployment - A configuration of all the terms mentioned that you use to deploy as a unit to the cluster.

HPR2959: Interview with Josh Clements about gpodder.net

Dec 5, 2019


In today's show Ken interviews Josh Clements from the gpodder.net project.

Josh answered the call to arms he heard on the Ubuntu Podcast. We discuss the plan and explain how you can also get involved.

Links https://github.com/gpodder/mygpo/blob/master/maintainer-needed.md https://ubuntupodcast.org/2019/08/08/s12e18-pilotwings/ https://github.com/gpodder/ https://gpodder.github.io/docs/mailing-list.html https://feeds.gpodder.net/ https://prgmr.com/xen/ support@gpodder.net

HPR2958: Haskell modules

Dec 4, 2019


With small programs it’s easy enough to have all code in single file. But as the program grows, you eventually want to organize things into separate files. In this episode I’ll talk a bit how to define modules and how to use them.


Each module is defined in separate file. In our example, we have file called multiplexer.hs, which contains our module definition.

At the beginning of the file, we have following:

module Multiplexer (mix, match, Plexer, Scooper(..)) where ....

We’re omitting actual function and type definitions as they aren’t important to this episode. In any case, there’s two functions: mix and match and two types: Plexer and Scooper that module exports (that is, these are available outside of the module). Plexer is imported as a type only and Scooper with field accessors or value constructors depending if it’s a record or algebraic datatype.

Using modules

In order to be able to use identifiers defined in separate module, we have to import them into our current one. In our imaginary program, we have main.hs that defines entry point for our program and we would like to import the definitions from Multiplexer module.

Easiest one is to just have import Multiplexer at the start of the main. This brings all exported identifiers from Multiplexer and we can then use them. Both qualified and unqualified names are imported. Qualified means name is prepended with module name: Multiplexer.mix instead of just mix.

If we want, we can specify what exactly should be imported: import Multiplexer (mix, match). This causes only functions mix and match be imported, while Plexer and Scooper are unavailable for us. Again, both qualified and unqualified names are imported.

In case we want only qualified names, we’ll write import qualified Multiplexer. After this mix isn’t available, but Multiplexer.mix is (and all the other identifiers exported by Multiplexer).

Sometimes module name is long and tedious to repeat when using qualified names. In these cases, renaming module while importing is a good option. This can be done by writing import Multiplexer as M. After this, instead of Multiplexer.mix you write M.mix.

Final thing I’m going to mention is importing everything else except specified identifiers. This is done by writing import Multiplexer hiding (mix). This imports everything exported by Multiplexer, except mix.


There are many ways of importing and they can be mixed. Here’s a list of them:

import Multiplexer import Multiplexer () import Multiplexer (mix, match, Plexer, Scooper(..)) import qualified Multiplexer import qualified Multiplexer (mix, match, Plexer, Scooper(..)) import Multiplexer hiding (mix, match) import qualified Multiplexer hiding (Plexer, Scooper) import Multiplexer as M import Multiplexer as M (mix, match) import qualified Multiplexer as M import qualified Multiplexer as M (Plexer, Scooper(..))

In short:

Some identifiers can be chosen to be imported, while leaving others unimported Modules can be imported qualified (forcing an obligatory namespace qualifier to imported identifiers). Some identifiers can be skipped via the hiding clause. The module namespace can be renamed, with an as clause. Prelude

Prelude is base module containing lots of helpful types and functions, which is automatically imported by every module. If this is not what you want, there’s two options. First one is to use pragma at start of the file: {-# LANGUAGE NoImplicitPrelude #-}, which causes Prelude not to be imported. Another one is to manually import Prelude, which turns of automatic import: import qualified Prelude as P.


When system grows, it’s helpful to break it into more manageable pieces. For this we use modules. import is used to bring identifiers from other modules into current one.

Questions, comments and feedback is welcomed. Best way to reach me is either email or in fediverse where I’m tuturto@mastodon.social

HPR2957: Lord D's Film Reviews: Ever

Dec 3, 2019


Written/Directed by Josh Beck
Starring Wendy McColm & Christina Elizabeth Smith
Cinematography by Micah Van Hove
Running Time: 1:37:42


A young woman named Ever, while grieving over a devastating loss, meets Emily, who helps her to heal and find love again.

HPR2956: HPR Community News for November 2019

Dec 2, 2019


table td.shrink { white-space:nowrap } New hosts

Welcome to our new hosts:
Nihilazo, Daniel Persson.

Last Month's Shows Id Day Date Title Host 2935 Fri 2019-11-01 The work of fire fighters, part 3 Jeroen Baten 2936 Mon 2019-11-04 HPR Community News for October 2019 HPR Volunteers 2937 Tue 2019-11-05 Lord D's Film Reviews: His Girl Friday lostnbronx 2938 Wed 2019-11-06 Naming pets in space game tuturto 2939 Thu 2019-11-07 Submit a show to Hacker Public Radio in 10 easy steps b-yeezi 2940 Fri 2019-11-08 Better Social Media 05 - Mastodon Ahuka 2941 Mon 2019-11-11 Server Basics 107: Minishift and container management klaatu 2942 Tue 2019-11-12 Why I love lisps Nihilazo 2943 Wed 2019-11-13 Music as Life brian 2944 Thu 2019-11-14 ONICS Basics Part 4: Network Flows and Connections Gabriel Evenfire 2945 Fri 2019-11-15 Saturday at OggCamp Manchester 2019 Ken Fallon 2946 Mon 2019-11-18 Sunday at OggCamp Manchester 2019 Ken Fallon 2947 Tue 2019-11-19 The Mimblewimble Protocol mightbemike 2948 Wed 2019-11-20 Testing with Haskell tuturto 2949 Thu 2019-11-21 Grin and Beam: The 2 major mimblewimble blockchains mightbemike 2950 Fri 2019-11-22 NotPetya and Maersk: An Object Lesson Ahuka 2951 Mon 2019-11-25 A walk through my PifaceCAD Python code – Part 2 MrX 2952 Tue 2019-11-26 Publishing your book using open source tools Jeroen Baten 2953 Wed 2019-11-27 How I got started in Linux Archer72 2954 Thu 2019-11-28 Wrestling As You Like It episode 1 TheDUDE 2955 Fri 2019-11-29 Machine Learning / Data Analysis Basics Daniel Persson Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 16 comments in total.

Past shows

There are 2 comments on 1 previous show:

hpr1585 (2014-08-29) "36 - LibreOffice Calc - Financial Functions - Loan Payments" by Ahuka. Comment 1: timttmy on 2019-11-30: "Thanks" Comment 2: Ahuka on 2019-11-30: "I'm glad it helped"
This month's shows

There are 14 comments on 8 of this month's shows:

hpr2935 (2019-11-01) "The work of fire fighters, part 3" by Jeroen Baten. Comment 1: Ken Fallon on 2019-11-05: "That sucks"Comment 2: Ken Fallon on 2019-11-05: "That blows"Comment 3: Ken Fallon on 2019-11-05: "You're Fired"
hpr2936 (2019-11-04) "HPR Community News for October 2019" by HPR Volunteers. Comment 1: lostnbronx on 2019-11-04: "Ken's Voice Is Better Than espeak"Comment 2: Jon Kulp on 2019-11-05: "Pots"Comment 3: clacke on 2019-11-19: "Release order or episode order?"
hpr2939 (2019-11-07) "Submit a show to Hacker Public Radio in 10 easy steps" by b-yeezi. Comment 1: Ken Fallon on 2019-11-07: "Clarification"
hpr2940 (2019-11-08) "Better Social Media 05 - Mastodon" by Ahuka. Comment 1: ClaudioM on 2019-11-08: "Simple Mastodon Timeline View Option"
hpr2942 (2019-11-12) "Why I love lisps" by Nihilazo. Comment 1: tuturto on 2019-11-12: "welcome"Comment 2: Carl on 2019-11-21: "Well Done"Comment 3: gerryk on 2019-11-22: "loved it"
hpr2943 (2019-11-13) "Music as Life" by brian. Comment 1: Carl on 2019-11-21: "Interesting Episode"
hpr2944 (2019-11-14) "ONICS Basics Part 4: Network Flows and Connections" by Gabriel Evenfire. Comment 1: Dave Morriss on 2019-11-27: "This is wonderful"
hpr2955 (2019-11-29) "Machine Learning / Data Analysis Basics" by Daniel Persson. Comment 1: b-yeezi on 2019-11-29: "Great first episode"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-November/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Stand at FOSDEM

Our proposal for a “Free Culture Podcasts” stand at FOSDEM was accepted for the Sunday 2nd February. This is fantastic news as this is the largest FLOSS event in Europe and is absolutely thronged the whole day.


Anyone going to FOSDEM, and who would like to help staff the booth on Sunday please get in touch.

Tags and Summaries

Thanks to the following contributor for sending in updates in the past month: Dave Morriss

Over the period tags and/or summaries have been added to 5 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2955: Machine Learning / Data Analysis Basics

Nov 29, 2019


In this episode, I talk about different techniques that we can use to predict the outcome of some question depending on input features.

The different techniques I will go through are the ZeroR and OneR that will create a baseline for the rest of the methods.

Next up, we have the Naive Bayes classifier that is simple but powerful for some applications.

Nearest neighbor and Decision trees are next up that requires more training but is very efficient when you infer results.

Multi-layer perceptron (MLP) is the first technique that is close to the ones we usually see in Machine Learning frameworks used today. But it is just a precursor to Convolutional Neural Network (CNN) because of the size requirements. MLPs have the same size for all the hidden layers, which makes it unfeasible for larger networks.

CNNs, on the other hand, uses subsampling that will shrink the layer maps to reduce the size of the network without reducing the accuracy of the predictions.

Links Some references for further reading on Wikipedia. https://en.wikipedia.org/wiki/Naive_Bayes_classifier https://en.wikipedia.org/wiki/Nearest_neighbor_search https://en.wikipedia.org/wiki/Decision_tree https://en.wikipedia.org/wiki/Support-vector_machine https://en.wikipedia.org/wiki/Multilayer_perceptron https://en.wikipedia.org/wiki/Convolutional_neural_network A video I made some years ago where you can see some visual aids for this subject.

HPR2954: Wrestling As You Like It episode 1

Nov 28, 2019


TV and pro wrestling go hand in hand. Both have fed off of each other, and with the internet we are now exposed to many different promotions with their own visual style in order to broadcast wrestling in the ring.

HPR2953: How I got started in Linux

Nov 27, 2019


Osdisc.com is the website that I mentioned while distro hopping. Unfortunately, as of August 2019, their site is no longer sending CD’s/DVD’s.

How I recorded:
Android phone, lapel mic, and Audio Recorder app found here:


And here:


HPR2952: Publishing your book using open source tools

Nov 26, 2019


Printing on demand website: https://www.lulu.com

HPR2951: A walk through my PifaceCAD Python code – Part 2

Nov 25, 2019



The script being discussed in this show is available for download with this show: cad-menu.py

GENERIC FUNCTIONS def get_hpr_que():
Goto hacker public stats page and extract the number of days to next free slot turns on blinkstick LED with colour dependent on the number of days to next free slot in HPR queue prints number of days to next free slot to the display GENERIC BLINKSTICK FUNCTIONS

def bstick_off():
Search for all attached blinksticks and turn them all off

def bstick_on(colour):
Turn blinkstick on and set led colour to string value stored in var colour. valid colours are, black, silver, gray, white, maroon, red, purple, fuchsia, green, lime, olive, yellow, navy, blue, teal, aqua

def bstick_on_random():
Turn blinkstick on colour random

def bstick_blink(colour):
Turn blinkstick on with supplied colour


def run_cmd(cmd):
Used to run an external linux command

def get_my_ip():
Returns ip address

def get_my_essid():
Returns wifi ESSID

def get_my_wifi_strength():
Returns wifi signal strength as a percentage

def wait_for_ip():
Tries 10 times to get IP address

def show_wifi_info():
Show WiFi information on display, shows essid on first line and both the wifi signal strength as a percentage and ip address on the second line.

def custom_bitmaps():
Selection of custom bitmaps to use on LCD display

Article in pifacecad documentation giving details about creating custom bitmaps on the pifacecad

This tool referenced in the pifacecad documentation link above can help design custom bitmaps. Make sure you select 5x8

def writelongstring(longstring):
Writes a long string to the piface control and display LCD & scrolls it to the left until the last character appears on the right hand side of the screen

# Local Variables (for function writelongstring) DisplaySize = 15 # Number of characters that can be displayed on 1 line of display StepSize = 4 # Step size when scrolling message on display ScrollSpeed = 0.55 # Adjusts scroll speed, delay in seconds between scrolls Scroll = 0 # Default value for scroll, used when string is smaller than display size

def init_display():
# Setup LCD display for selected menu 0 (Podcasts), 1 (Audiobooks), 2 (System)

def display_main_menu(event):
# Clear LCD & dsplays the appropriate main menu message

HPR2950: NotPetya and Maersk: An Object Lesson

Nov 22, 2019


We previously looked at the NIST Security Framework, which lays out how organizations should manage their network security. That may have seemed a bit dry, so let’s look at this case study to put some flesh on those dry bones. Failing to manage your security risks properly can have significant consequences.

Links: https://www.zwilnik.com/?page_id=997 http://hackerpublicradio.org/eps.php?id=2850 http://www.zwilnik.com/?page_id=1045

HPR2949: Grin and Beam: The 2 major mimblewimble blockchains

Nov 21, 2019


Last time we reviewed the mimblewimble protocol for blockchain networks. This is an innovative protocol focused on privacy and scalability.

In this episode we take a closer look at the two major implementations of mimblewimble, called Grin and Beam. They are both interesting projects that take very different approaches, yet both have managed to launch working blockchains that preserve the core strengths of the protocol.

HPR2948: Testing with Haskell

Nov 20, 2019



I have liked writing automated tests for a long time, so it’s not a surprise that I end up writing them in Haskell too. This is very broad topic, so this episode only scratches the surface.


HSpec is testing framework that automatically detects tests, like most of the modern systems. It supports hierarchies, so one can organize tests by feature for example.

spec :: Spec spec = do describe "Very important feature" $ do it "Execution should be error free" $ do ... it "Flux capacitors can be charged" $ do ... describe "Somewhat less important feature" $ do ... Unit test

Unit test tests a single case with fixed set of inputs. With pure functions these are a pleasure to write as they’re really just data in, data out, verify results. Below is two examples:

spec :: Spec spec = do describe "Markov chain configuration" $ do it "Adding new starting element to empty configuration creates item with frequency of 1" $ do let config = addStart ("AA" :: DT.Text) emptyConfig config ^? (configStartsL . _head . itemFreqL) `shouldBe` Just 1 config ^? (configStartsL . _head . itemItemL . _Just) `shouldBe` Just "AA" it "Adding same element twice to empty configuration creates item with frequency of 2" $ do let config = addStart "AA" $ addStart ("AA" :: DT.Text) emptyConfig config ^? (configStartsL . _head . itemFreqL) `shouldBe` Just 2 config ^? (configStartsL . _head . itemItemL . _Just) `shouldBe` Just "AA"

Both are for testing configuring markov chains. First one checks that adding a starting element in empty configuration results correct item with correct weight being added. Second checks that adding same starting element twice results weight of 2.

Both tests use lenses for reading nested data structure. Episode doesn’t cover them much at all, as it’s enough to know that (configStartsL . _head . itemFreqL) focuses on starting elements of configuration, selects first item of the list and then selects frequency of that item. Lenses can also be used for modifying data and they don’t have to focus on only one element.

Unit tests are easy enough to write, they verify single thing about the unit being tested and are usually super fast to run and not error prone.

Property based test

Property based tests are used to check that a certain property holds with randomly generated input parameters. I’m using HSpec as testing framework and QuickCheck as tool for generating test data:

spec :: Spec spec = do describe "planets" $ do describe "food" $ do it "food requirement for positive amount of population is more than zero" $ do forAll positivePopulation $ \x -> foodRequirement x > RawResource 0 it "food base production for farms is equal or greater than their amount" $ do forAll someFarms $ \x -> (sum (fmap foodBaseProduction x)) > (RawResource $ length x)

Above we have to tests. First one checks that with any non-zero population, foodRequirement is greater than 0. Second one check that with any positive amount of farm, foodBaseProduction is greater than amount of the farms.

positivePopulation is Generator, that is used by QuickCheck to generate random data for testing. Its definition is shown below:

singlePopulation :: Gen PlanetPopulation singlePopulation = do let aPlanetId = toSqlKey 0 let aRaceId = toSqlKey 0 aPopulation <- arbitrary `suchThat` \x -> x > 0 return $ PlanetPopulation aPlanetId aRaceId aPopulation positivePopulation :: Gen [PlanetPopulation] positivePopulation = do k <- arbitrary `suchThat` \x -> x > 0 vectorOf k singlePopulation

Generated data can be really simple or very complex. Generating complex data is often convenient to break into smaller steps and write generators for them.

Property based tests are somewhat harder to write than unit tests, but they can potentially cover edge cases that might otherwise not been discovered.

Working with database

All tests shown so far have been testing pure code, that is, code that is data in, data out. When database is introduced, things get more complicated. Suddenly there’s much more possibilities for errors. Below is an example of such a test:

spec :: Spec spec = withApp $ do describe "Status handling" $ do describe "Planet statuses" $ do it "Expired planet statuses are removed and news created" $ do sId <- runDB $ insert $ StarSystem { starSystemName = "Aldebaraan" , starSystemCoordX = 10 , starSystemCoordY = 20 , starSystemRulerId = Nothing } fId <- runDB $ insert $ Faction { factionName = "Star lords" , factionHomeSystem = sId , factionBiologicals = 10 , factionMechanicals = 10 , factionChemicals = 10 } pId1 <- runDB $ insert $ Planet { planetName = "New Earth" , planetPosition = 3 , planetStarSystemId = sId , planetOwnerId = Just fId , planetGravity = 1.0 , planetRulerId = Nothing } _ <- runDB $ insert $ PlanetStatus { planetStatusPlanetId = pId1 , planetStatusStatus = GoodHarvest , planetStatusExpiration = Just 20201 } let status = Simulation 20201 _ <- runDB $ insert status news <- runDB $ removeExpiredStatuses (simulationCurrentTime status) statuses <- runDB $ selectList [ PlanetStatusPlanetId ==. pId1 ] [] loadedNews <- runDB $ selectList [] [ Asc NewsDate ] liftIO $ statuses `shouldSatisfy` (\x -> length x == 0) liftIO $ news `shouldSatisfy` (\x -> length x == 1) liftIO $ loadedNews `shouldSatisfy` (\x -> length x == 1)

There’s a lot more code that had to be written for this test and majority of it is for setting up database state. The test if for ensuring that when good harvest boost expires, it is removed from database and respective news article is created.

These kinds of tests have a lot more code and are much more slower to run because of the communication with a database. There’s also more cases where something can go wrong. But in the end, these kinds of tests are needed if one wants to verify that interaction with database is working as planned.

Testing API

Last example is about testing REST API. There are two tests, where the first one is checking that proper access control is in place and second one checks that pending messages are correctly retrieved.

spec :: Spec spec = withApp $ do describe "Message handling" $ do it "unauthenticated user can't access messages" $ do _ <- get ApiMessageR statusIs 401 it "pending messages are loaded" $ do (pId, fId) <- setupPerson _ <- runDB $ insert $ researchCompleted 25250 fId HighSensitivitySensors user <- createUser "Pete" (Just pId) authenticateAs user _ <- get ApiMessageR resp <- getResponse let jsonM = join (decode <$> simpleBody <$> resp) :: Maybe Value assertEq "message tag" (jsonM ^? (_Just . _Array . _head . key "tag" . _String)) (Just "ResearchCompleted") assertEq "star date" (jsonM ^? (_Just . _Array . _head . key "starDate" . _Integer)) (Just 25250) assertEq "technology" (jsonM ^? (_Just . _Array . _head . key "contents" . key "Technology" . _String)) (Just "HighSensitivitySensors") statusIs 200

Here extra complication is created by the fact that many features of the system are behind authentication and authorization. Luckily Yesod comes with helper function authenticateAs, that allows code to authenticate when system is running in development mode.

These test are even slower than any of the previous ones, but on the other hand, they test whole chain from user interaction to database and back.

In closing

There’s lots of things that I couldn’t cover in such a short time, like various types of tests: UI testing, performance testing, security testing, long running testing…, the list goes on and on. But hopefully this episode gave you ideas what kinds of tests one can write and how to get started doing so using Haskell.

Best way to reach me is email or at fediverse, where I’m tuturto@mastodon.social.

HPR2947: The Mimblewimble Protocol

Nov 19, 2019


Financial privacy is critical for adoption of cryptocurrency as a means of exchange. Individuals worry about employers monitoring their spending details, insurers increasing rates based on purchases and landlords raising rents when they get a promotion. Businesses can only operate using cryptocurrency if they can prevent disclosure of vendor payments, rates paid to suppliers, payroll details, and so on. At the same time, they need to selectively disclose financial data to governments and might need to demonstrate compliance in some industries.

Mimblewimble is a new protocol that uses cryptography to achieve striking reductions in blockchain size, so users can run a full node on low powered devices like phones. It offers the strongest privacy protection assurances around, through a variety of clever tricks. For one thing, transaction history is not recorded, which also results in a smaller blockchain. There are no addresses and no transaction amounts are recorded.

We’re not going to focus on the cryptography, although it’s a fascinating example of just how much progress is being made in recent years. We’ll focus instead on what makes this mysterious network protocol unique among cryptocurrencies.

HPR2946: Sunday at OggCamp Manchester 2019

Nov 18, 2019


beni, Andrew Conway/mcnalu, Timttmy, and Dave at the HPR booth.

Michael from Electric Flap Jack Custom Built Guitars, and author of Fretboard Template Generator available on GitHub

Perspex template for carving the body and neck.

A work in progress.

Tools for making guitar, including the tool to round the frets.

And of course you need a guitar stand.

Fretboard Template Generator available on GitHub

Tai Kedzierski hanging out with "Grumpy" Mike Cook.

Mike produces electronic musical instruments for people with accessibility issues.

He also has a book called Arduino Music and Audio Projects to help you do this yourself.

At Drake Music we are leaders in music, disability and technology.
We are innovators, educators, curators and advocates. We believe everyone has the right to express themselves creatively through music. We use new technologies and ideas to open up access to music for all. Our vision is a world where disabled and non-disabled musicians work together as equals.

The bat base.

The Cattle Caster.

The Arduino Caster

The Open Rights Group.
Open Rights Group protects the digital rights of people in the UK including privacy and free speech online. We are funded by over 3,000 people like you.

Manchester Grey Hats

Manchester Grey Hats is a place for all those interested in hacking and cyber security to learn and share. We run capture the flags, workshops and perform/present security research.

We encourage all skill levels and those from all backgrounds. Are you an aspiring hacker or a developer thinking about security? Come along and learn. Presenting is open to all members, so if you have something you’d like to present but aren’t ready for the big conferences, get in touch.

Said best by The Mentor – “This is our world now… the world of the electron and the switch, the beauty of the baud”

Although we meet face to face once a month, MGH is mostly an online community. We encourage people to join us in person for workshops and events but if you can't, join us on Slack and our live stream.

An example of the of the locks that needed to be picked for the FlawCon Capture the Flag event.

How to hold the lock while you are picking it.

HPR2945: Saturday at OggCamp Manchester 2019

Nov 15, 2019


OggCamp is an unconference celebrating Free Culture, Free and Open Source Software, hardware hacking, digital rights, and all manner of collaborative cultural activities and is committed to creating a conference that is as inclusive as possible.
This year a team of HPR volunteers hit the show.

Ken's recording kit and some of the stickers.

Dave, Andrew Conway/mcnalu and Timttmy getting the booth ready.

Only HPR hosts can sign the booth.

Yannick signs the booth.

Timttmy's script to turn an Android phone into a webcam. Two versions of the script to take a screenshot and post it to the web.

Surveillance state ?

Our latest host Nihilazo signs the booth.

An Interview with Ban Parsons from the Matrix An open network for secure, decentralized communication

An Interview with mystorm.uk makers of the open FPGA. An FPGA chip is a re-programmable piece of silicon hardware, it can be reconfigured or programmed to a logic circuit of your own design.
In 2016 we decided to setup up the myStorm project in order to build OpenSource FPGA hardware. Several years later we are building the 5th generation of BlackIce Development boards. BlackIce Mx the latest generation of our hardware has been built using BlackEdge open hardware standard which enable the 'Core' Board IceCore to be separated from its carrier board which provides MixMod and Pmod hardware add-ons. Please take a look at the myStorm forum to ask questions and participate in our community.

An Interview with Erik Grun of the Free Software Foundation Europe about their campaign for Public Money? Public Code!

HPR2944: ONICS Basics Part 4: Network Flows and Connections

Nov 14, 2019


Terminology connection - a bi-directional communication channel between two programs over a network client - the initiator of a connection server - the receiver of the connection port - a common term for the address of a program or service on a given machine 5-tuple - the combination of protocol, client machine network address, client port, server machine network address, server port that uniquely identifies a connection flow - a grouping of packets to be treated in a common way microflow - a flow with a fine level of granularity such as the packets from one direction of traffic in a connection The topflow.sh Script #!/bin/sh # Start a capture in the background that drops the packets # and just reports the flow events pktin $1 | nftrk -d -f /tmp/flows.txt & PID=$! # On CTRL-C clean kill the capture and clean up trap "kill $PID ; rm -f /tmp/flows.txt /tmp/topflows.txt /tmp/namecache.txt ; exit 0" INT TERM # Once per second do # look at the last 100 flows # sort them by 5-tuple # remove duplicates # convert ports, protocols and addresses to names # sort by data usage per flow in reverse order (highest first) # a little more pretty printing # only take the top 20 lines # clear the screen and print the result while [ 1 ] ; do tail -100 /tmp/flows.txt | sort -s -t '|' -k 3,3 | awk -f uniqflows.awk | awk -f prflow.awk | sort -s -t ',' -k 3 -r | awk -f columns.awk | head -20 > /tmp/topflows.txt clear cat /tmp/topflows.txt sleep 1 done

You can find the complete code at: https://gitlab.com/onics/onics-examples

HPR2943: Music as Life

Nov 13, 2019


Thomas Orr Anderson
https://www.phisonics.com/about-2/ Find the audio that I listened to here

Background sounds provided by some road noise, and a train.

HPR2942: Why I love lisps

Nov 12, 2019


Syntax example (define (fib-rec n) (if (< n 2) n (+ (fib-rec (- n 1)) (fib-rec (- n 2))))) Structured Editing

Parinfer: https://shaunlebron.github.io/parinfer/

Paredit: https://www.emacswiki.org/emacs/ParEdit

Clojure libraries

core.match (adds pattern matching): https://github.com/clojure/core.match

core.logic (prolog-like stuff): https://github.com/clojure/core.logic

overtone: https://github.com/overtone/overtone

Other stuff

Clojure macro explanation: https://learnxinyminutes.com/docs/clojure-macros/


The little schemer: https://mitpress.mit.edu/books/little-schemer-fourth-edition

Clojure for the brave and true: https://www.braveclojure.com/

HPR2941: Server Basics 107: Minishift and container management

Nov 11, 2019


Learn "the OS of the cloud" with minishift or minikube

HPR2940: Better Social Media 05 - Mastodon

Nov 8, 2019


As mentioned earlier, Diaspora was one of the earliest alternative, privacy-respecting social media platforms, but it was focused on being an alternative to Facebook (and it has done this fairly well). But that leaves the other big platform of the social world, Twitter. Mastodon is a nice federated alternative to Twitter and a nicer place to be. https://www.zwilnik.com/?page_id=1034

Links: https://joinmastodon.org/ https://en.wikipedia.org/wiki/Identi.ca http://pump.io/ https://en.wikipedia.org/wiki/Gamergate_controversy https://blog.joinmastodon.org/2018/07/cage-the-mastodon/ https://mastodon.social/about/more https://instances.noct.zone/ https://instances.social/list#lang=&allowed=&prohibited=&users= https://mwl.io/ https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md https://www.zwilnik.com/?page_id=1034

HPR2939: Submit a show to Hacker Public Radio in 10 easy steps

Nov 7, 2019


Steps Record your episode Go to http://hackerpublicradio.org Click on "Give Shows" Click on "Calendar" (the link is not obvious, so use your browser's find functionality to search for the word "Calendar").
Edit: Please use the ⇧Upload⇧ link in the menu bar Choose a slot Submit your email address Click the link in the confirmation email Create your profile (if new), then fill in the form with title, summary and show notes Attach your episode and submit (wait for long upload process) Receive your confirmation email, and enjoy your episode!

HPR2938: Naming pets in space game

Nov 6, 2019



In the two previous episodes we built a weighted list and used that to build markov chains. This time we’re going to use them to generate some names based on examples. I’m skipping over a lot of uninteresting code in this episode, concentrating only the parts that deal with names.


Person in game might hear scurrying sounds inside walls of their quarters. Then they have option of getting a cat, taming a rat or letting someone else deal with the problem. Depending on their choice, they might end up with a cat or a rat, that of course needs a name. Game offers 3 different options of names that haven’t been used before and person can always opt for completely random one.


While we’re not going to dig very deep into making configurations for markov chains, we can have look at the overall process.

We have list of names to serve as examples and three functions, which implementation I won’t delve into:

start for adding starting element links for recording link between two elements end adds ending element

addName function is used to add single name into config:

addName :: Int -> Text -> Config Text -> Config Text addName n s config = links pairs $ end elements $ start elements config where elements = chunksOf n s pairs = zip elements (safeTail elements)

First s (name) is split into strings of length n. These elements are then combined into pairs, where consecutive elements form a pair. Final step is to add start and ending elements into config, followed by links between elements of pairs.

We can then fold a list of examples into config:

nameConfig :: [Text] -> Int -> Config Text nameConfig xs n = foldr (addName n) emptyConfig xs

This starts with emptyConfig and calls addName repeatedly until all elements of list containing examples have been processed.


Now that we have configuration, we can start generating names. As usual, I like to keep things specific and generate PetName instead of just Text. I happened to have list of ancient greek names at hand, so I used that. Later on we’ll have to add more cultures, like Romans, Parthians, Persians, Germans, Phoenicians and so on.

General implementation of generating infinite list of strings of specific kind is shown below:

names :: (RandomGen g, Eq b) => (Text -> b) -> Config Text -> g -> [b] names t config g = nub $ (t . toTitle . concat) <$> chains config g

It’s easier to read if you start from right. chains config g generates infinite list of markov chains with given configuration. Next we create a new function (t . toTitle . concat), which uses concat to combine list of Text into single Text, toTitle to capitalize is correctly and t to transform it to something (PetName in our case). <$> is then used to apply this function to each element of our infinite list. Finally nub is used to remove duplicate entries.

With names we can then define petNames:

petNames :: (RandomGen g) => g -> [PetName] petNames = names MkPetName greekNameConfig

MkPetName is value constructor that turns Text into PetName (this is t used by names function).


Pets are currently very much work in progress. They have few attributes and there can be two different kinds of pets:

Pet json name PetName type PetType dateOfBirth StarDate dateOfDeath StarDate Maybe ownerId PersonId deriving Show Read Eq data PetType = Cat | Rat deriving (Show, Read, Eq, Ord, Enum, Bounded)

The actual beef is namingPetEvent function. When applied with Entity Person, Entity Pet and StarDate, it will create News that can be saved into database and later on showed to player. While the code is shown below, I’m not going to go over it line by line:

namingPetEvent :: (PersistQueryRead backend, MonadIO m, BaseBackend backend ~ SqlBackend) => Entity Person -> Entity Pet -> StarDate -> ReaderT backend m News namingPetEvent personE petE date = do pets <- selectList [ PetOwnerId ==. (entityKey personE) , PetDateOfDeath ==. Nothing ] [] let names = (petName . entityVal) <$> pets g <- liftIO getStdGen let availableNames = take 3 $ filter (\x -> not (x `elem` names)) $ petNames g let content = NamingPet (NamingPetEvent { namingPetEventPersonId = entityKey personE , namingPetEventPetId = entityKey petE , namingPetEventPetType = (petType . entityVal) petE , namingPetEventDate = date , namingPetNameOptions = availableNames }) [] Nothing return $ mkPersonalSpecialNews date (entityKey personE) content

General idea is to use selectList to load living pets of given person and then extract their names. With random generator g, we create a infinite list of PetNames, remove already used names from it and take 3 first ones. These names are then used to create NamingPetEvent.

In closing

Names are probably one of the most common applications of markov chains in games. Same technique can be used to generate nonsense books and articles that look realistic on a glance.

Questions, comments and feedback is welcomed, best way to reach is email or in fediverse where I’m tuturto@mastodon.social. Or even better, record your own episode for Hacker Public Radio.

ad astra!

HPR2937: Lord D's Film Reviews: His Girl Friday

Nov 5, 2019


Ignore the address for the film that I give in the review. Here’s a MUCH better copy than the one I watched. It’s another upload on Archive.org:


Boy, I wish I’d found this one first!

HPR2936: HPR Community News for October 2019

Nov 4, 2019


table td.shrink { white-space:nowrap } New hosts

Welcome to our new host:

Last Month's Shows Id Day Date Title Host 2912 Tue 2019-10-01 Stardrifter RPG Playtest Part 06 lostnbronx 2913 Wed 2019-10-02 Windows, SDN, and Firewalls Beto 2914 Thu 2019-10-03 Describing how I listen to podcasts PART 4 MrX 2915 Fri 2019-10-04 Intro - My Recording Setup Carl 2916 Mon 2019-10-07 HPR Community News for September 2019 HPR Volunteers 2917 Tue 2019-10-08 Stardrifter RPG Playtest Part 07 lostnbronx 2918 Wed 2019-10-09 Selecting random item from weighted list tuturto 2919 Thu 2019-10-10 hosting software in HPR show notes Jezra 2920 Fri 2019-10-11 Better Social Media 03 - MeWe Ahuka 2921 Mon 2019-10-14 Geocaching with the family thelovebug 2922 Tue 2019-10-15 Stardrifter RPG Playtest Part 08 lostnbronx 2923 Wed 2019-10-16 Describing how I listen to podcasts PART 5 MrX 2924 Thu 2019-10-17 Hacking an Alarm Clock to Make it Quieter Jon Kulp 2925 Fri 2019-10-18 LinuxLugCast's Memorial for FiftyOneFifty Honkeymagoo 2926 Mon 2019-10-21 Full Circle Magazine Tony Hughes AKA TonyH1212 2927 Tue 2019-10-22 Stardrifter RPG Playtest Part 09 lostnbronx 2928 Wed 2019-10-23 Building markov chains with Haskell tuturto 2929 Thu 2019-10-24 Recovering Files from a Dead MacBook Air Jon Kulp 2930 Fri 2019-10-25 Better Social Media 04 - Diaspora Ahuka 2931 Mon 2019-10-28 Wallabag for on premises article aggregation b-yeezi 2932 Tue 2019-10-29 Stardrifter RPG Playtest Part 10 lostnbronx 2933 Wed 2019-10-30 A walk through my PifaceCAD Python code – Part 1 MrX 2934 Thu 2019-10-31 Server Basics 106: Namespaces and containers klaatu Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 14 comments in total.

Past shows

There are 7 comments on 5 previous shows:

hpr2895 (2019-09-06) "The work of fire fighters, part 2" by Jeroen Baten. Comment 3: Don on 2019-10-20: "great podcast"
hpr2900 (2019-09-13) "Better Social Media 01 - Introduction" by Ahuka. Comment 1: Jeroen baten on 2019-10-05: "Hope you will find time to discuss Okuna" Comment 2: Kevin O'Brien on 2019-10-05: "No plans for now"
hpr2906 (2019-09-23) "Feature Engineering for Data-Driven Decision Making" by b-yeezi. Comment 2: Gabriel Evenfire on 2019-10-08: "Love the idea here..."
hpr2909 (2019-09-26) "ONICS Basics Part 3: Networking Fundamentals" by Gabriel Evenfire. Comment 2: Gabriel Evenfire on 2019-10-08: "Thanks for the feedback" Comment 3: gerryk on 2019-10-17: "Yet another top episode"
hpr2911 (2019-09-30) "my internet connection" by Jezra. Comment 1: Beeza on 2019-10-05: "HPR 2911"
This month's shows

There are 7 comments on 5 of this month's shows:

hpr2913 (2019-10-02) "Windows, SDN, and Firewalls" by Beto. Comment 1: ClaudioM on 2019-10-02: "+1 on Chocolatey Recommendation"
hpr2915 (2019-10-04) "Intro - My Recording Setup" by Carl. Comment 1: Ken Fallon on 2019-10-04: "More shows on ...."
hpr2921 (2019-10-14) "Geocaching with the family" by thelovebug. Comment 1: jezra on 2019-10-17: "what a fun adventure"Comment 2: Kevin O'Brien on 2019-10-17: "I loved the show"
hpr2925 (2019-10-18) "LinuxLugCast's Memorial for FiftyOneFifty " by Honkeymagoo. Comment 1: lostnbronx on 2019-10-19: "I Never Met Fifty, But I Knew Him"
hpr2928 (2019-10-23) "Building markov chains with Haskell" by tuturto. Comment 1: b-yeezi on 2019-10-29: "Thanks for this episode"Comment 2: tuturto on 2019-10-31: "thanks for the feedback!"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-October/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business FLOSS Weekly

Ken Fallon and Ahuka appeared on FLOSS Weekly Episode 553 on October 30th 2019 to talk about Hacker Public Radio.

OggCamp 2019

There was an HPR presence at OggCamp 2019. This was held at The Manchester Conference Centre during the weekend of October 19th and 20th 2019. We had an HPR table, which was manned by many HPR hosts and received many visitors. Ken recorded interviews which will be released later in November.


A request has been made to get a Podcasters table at FOSDEM 2020.

HPR on podcast networks

We need some help getting HPR on Google Podcasts, Stitcher, Soundcloud, etc.

Ken versus espeak

Which is preferable, the espeak show summary or Ken’s new reading of the information?

Watching Star Wars for the first time

A question: should it be watched in Episode or Production Order?

Tags and Summaries

There were no tag or summary updates in the past month.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2935: The work of fire fighters, part 3

Nov 1, 2019


Continued general basic knowledge of fire fighting.

Talking about large water system, breathing gear, “the walk”, flash-over and back-draft.

HPR2934: Server Basics 106: Namespaces and containers

Oct 31, 2019


Namespaces provide context and constraints for processes on a Linux system. They are utilised by the infrastructure of "the cloud" to create distinct "containers", in which processes may run without awareness of the system they are actually running upon.

// prove you are not running some process $ pidof tcsh // nothing $ sudo pidof tcsh // nothing // launch tcsh in a new namespace with unshare: $ sudo unshare --fork --pid --mount-proc tcsh // from within that session: # pidof tcsh 1 // wait what?? // yes tcsh is the first pid of its own namespace // from another term $ ps 1 init $ pidof tcsh 26814 // from inside the namespace, pid is seen as 1 // from outside, pid is normal $ ps tree | less // search for tcsh // See evidence of namespaces: $ ls /proc/*/ns $ ls /proc/26814/ns ipc net pid user uts [...]

To see this in action for a slightly more pragmatic purpose, you can use the lxc command. The LXC system uses namespaces and cgroups to create functional containers that act, more or less, like a Virtual Machine, except that they are built in containers so that they do not have to emulate hardware.

If your system doesn't have LXC installed, first install it:

$ sudo dnf install lxc lxc-templates lxc-doc // on Ubuntu or Debian: $ apt install lxc

You also need to create a network bridge so that your container and your host system (that's the computer you're sitting in front of right now) can communicate.

$ sudo ip link add br0 type bridge $ sudo ip addr show br0 7: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 26:fa:21:5f:cf:99 brd ff:ff:ff:ff:ff:ff

Now give your bridge device an IP address that doesn't conflict with any existing IP address on your network:

$ sudo ip addr add dev br0 $ sudo ip link set br0 up

Create a configuration for your container. You can base this on the samples provided by lxc (located in /usr/share/docs/lxc or similar). Everything but veth, br0, and up is arbitrary. You can make up all the values.

lxc.utsname = hackerpublicradio lxc.network.type = veth lxc.network.flags = up lxc.network.link = br0 lxc.network.hwaddr = 4a:49:43:49:79:bd lxc.network.ipv4 = lxc.network.ipv6 = 2003:db8:1:0:214:c0ff:ee0b:3596

Now install an OS into your container. OS templates are provided by LXC in /usr/share/doc/lxc/templates or a similar location.

$ ls -m /usr/share/lxc/templates/ lxc-alpine, lxc-altlinux, lxc-archlinux, lxc-busybox, lxc-centos [...]

Choose a template and install. I use Alpine in the recorded show, because it's supposed to be really small. I don't necessarily recommend Alpine. I recommend Slackware, of course.

$ sudo lxc-create --name slackware --template slackware

Once the install is done, start your container:

$ sudo lxc-start --name slackware --rcfile ~/mycontainer.conf

Now attach to the container:

$ sudo lxc-attach --name slackware #

Run a command.

# uname -av Linux hackerpublicradio 5.3.0.x86_64 #1 SMP Wed Oct 10 18:34:01 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

This is the technology that Docker and OCI projects use to create containers. And when a bunch of containers start swarming around on a bunch of hosts, you eventually end up with a cloud. How do you manage all of these things? That will be the topic for the next entry in this series, I'll bet.

HPR2933: A walk through my PifaceCAD Python code – Part 1

Oct 30, 2019


In this series a do whirl wind tour of the Python code I developed to control my PifaceCAD raspberry pi add on board. I this use to control a music player running on a remote raspberry pi upstairs.

In this episode I cover my use of global variables.

List of global variables along with associated comments explaining what they are used for

# GLOBAL VARIABLES RemoteDevice = "pi@" # Username and ip address of the remote device to control SeekMin = -6 # Sets the minimum value of the variable SeekPosition SeekMax = 6 # Sets the maximum value of the variable SeekPosition SeekPosition = 0 # stores seek menu position, SeekMenu = False # used to track seek menu state, ie are we in seek menu or not FirstPass = True # Used to track 1st time button 5 (backlight toggle) is pushed, turns off blinkstick LcdLightOn = False # used to track toggle sate of backlight button 5 MenuMin = 0 # Sets the minimum value of variable "Menu" MenuMax = 2 # Sets the maximum value of variable "Menu" Menu = 0 # global variable used to keep trak of selected menu IrActive = False # used to track toggle state of active infrared buttons, when false disables # all buttons on the remote control except the blue button. StoredTime = 0 # Stores curent time in seconds when a button is pushed, used by double button tap feature #GET_IP_CMD = "hostname –all-ip-addresses" # Debian 7 wheezy, Command to get IP adress GET_IP_CMD = "hostname --all-ip-addresses | cut -d' ' -f1" # Debian 8 jessie, Command to get IP adress #GET_ESSID_CMD = "iwconfig wlan0 | grep 'ESSID:' | cut -d':' -f2" # Debian 7 wheezy, Command to get wifi ESSID GET_ESSID_CMD = "/sbin/iwconfig wlan0 | grep 'ESSID:' | cut -d':' -f2" # Debian 8 wheezy, Command to get wifi ESSID GET_WIFI_STRENGTH_CMD = "/sbin/iwconfig wlan0 | grep 'Link Quality=' | awk '{ print $2 }'" # Command to get wifi signal strength

HPR2932: Stardrifter RPG Playtest Part 10

Oct 29, 2019


This episode is Part 10 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

It’s not unusual for a game master to have two sets of maps for an adventure: one is for the players, which only has the sort of information on it that their characters might reasonably have access to; the other is NOT for the players, as it shows all the special information they shouldn’t know about (at least, not all at once). This is where you’d make note of secret doors, hidden objects or enemies, and/or, as in the case of this playtest, the physical condition of the ship as it stands at the moment.

Player Map
Player Map

Game Master Map
Game Master Map

Additionally, here’s a zip file containing the adventure, the maps, the floor plan descriptions, some miscellaneous non-player characters, and the Stardrifter RPG rules in EPUB format. Again, these are no longer the LATEST version of the rules, but they are what we used for these episodes.


In this final part of the mini-series, the players provide their hard-working game designer with some valuable feedback, observations, and general opinions!

Special thanks to my playtesters in this episode: Thaj, Mark (who was playing Brinn), and X1101!

HPR2931: Wallabag for on premises article aggregation

Oct 28, 2019



I forgot to mention that Wallabag is also offered as a service for a small fee. Check out the website for more information.

Links Wallabag website Wallabag documentation Wallabag on Docker Hub Cockpit website

HPR2930: Better Social Media 04 - Diaspora

Oct 25, 2019


I don’t know if Diaspora was the first of the alternatives to come along, but it was certainly the first I was aware of. It got a lot of attention for the college students who first put it together (and remember that Facebook was originally created by a college student, Mark Zuckerberg). The four students, Ilya Zhitomirskiy, Dan Grippi, Max Salzberg, and Raphael Sofaer, were inspired by a speech Eben Moglen gave to the Internet society’s New York Chapter, where he described centralized social networks as “Spying for free”. The students chose the name Diaspora, which is a Greek word that means a “scattered or dispersed population” to reflect the idea that instead of a centralized platform, Diaspora would consist of independent nodes, called pods, each running a copy of the free software which is open source and licensed under the GNU-AGPL-3.0 license. https://www.zwilnik.com/?page_id=1032

Links: https://diasporafoundation.org/ https://en.wikipedia.org/wiki/GNU_General_Public_License https://softwarefreedom.org/ https://web.archive.org/web/20111002003516/http://blog.diasporafoundation.org/2011/09/21/diaspora-means-a-brighter-future-for-all-of-us.html https://podupti.me/ ahuka@pod.haxxors.com https://pod.haxxors.com/i/394c80269066 https://www.zwilnik.com/?page_id=1032

HPR2929: Recovering Files from a Dead MacBook Air

Oct 24, 2019


I talk about becoming a household hero by recovering my wife's files from her dead MacBook Air. Her laptop would not boot, shutting down seconds into the process each time she tried to start it up. I used an Ubuntu Live CD (DVD), with the commands fdisk and fsck to repair the damaged filesystem on the Mac. It still wouldn't boot even with the repaired filesystem, but I was able to mount the drive and copy her files to a USB drive.

Links Blog post Howto: Repair/Fix MAC HFS+ Partition Using Ubuntu

HPR2928: Building markov chains with Haskell

Oct 23, 2019



Last time we built a weighted list, this time we’re using that to build markov chains. Wikipedia states that “A Markov chain is a stochastic model describing a sequence of possible events in which the probability of each event depends only on the state attained in the previous event.” and that they’re named after the Russian mathematician Andrey Markov.


We’re after generic system, hence parametrized data types.

First part is Configuration a that lists possible starting elements of chain and elements that can follow a particular element.

data Config a = Config { configStarts :: ![Item a] , configContinuations :: !(Map a [Item a]) } deriving (Show, Read, Eq)

Second part is Item a, that just holds single item that could appear in chain and relatively frequency for its appearance.

data Item a = Item (Frequency (Maybe a)) deriving (Show, Read, Eq)

We’re using Maybe a as in some cases there’s chance of element being last element in chain. Thus, Nothing will represent end of chain.

In previous episode, we implemented choose, but later on I decided to rename it to chooseM. So when you see chooseM, it’s just different name for what we implemented previously.

Building a chain

Since building a configuration depends on the case quite a bit, we’re just going to assume that we have one at hand.

Our chains are built by chainM :: (Ord a, RandomGen g) => Config a -> Rand g [a]. Given a config, it creates computation that when run will return list of a, which is our chain.

Implementation is fairly straightforward:

chainM config = do starter <- chooseM (itemToFreq <$> configStarts config) case join starter of Nothing -> return [] Just h -> do t <- tailOfChain config h return $ h : t

First we select item from starting elements. In case there isn’t one, result will be a empty list. Otherwise we use tailOfChain to compute rest of the list and return a list of starter element followed by that tail.

For tail we need to figure out first what possible elements there are that can follow a given element. This is done by candidates function. lookup finds a possible list of elements in configContinuations. We use itemToFreq to turn this list into frequencies. Since items might be Nothing (in case where there aren’t any suitable continuations present) and any continuation in the list might be Nothing (in case where this is possibly terminating element), we have to use (fmap . fmap) to apply itemToFreq to each possible element. Moreover, concat turns our Maybe [Frequency (Maybe a)] into [Frequency (Maybe a)], if we have Nothing at this stage, result will be an empty list [].

candidates :: (Ord a) => Config a -> a -> [Frequency (Maybe a)] candidates config x = concat $ (fmap . fmap) itemToFreq items where items = lookup x (configContinuations config)

That concat part could have been written as:

case (fmap . fmap) itemToFreq items of Nothing -> [] Just x -> x

and the end result would be identical.

Now that we know how to figure our possible continuation elements, we can implement computing tail of chain:

tailOfChain :: (Ord a, RandomGen g) => Config a -> a -> Rand g [a] tailOfChain config c = do item <- chooseM (candidates config c) case join item of Nothing -> return [] Just x -> do xs <- tailOfChain config x return $ x : xs

Function first select item from candidates. If there isn’t suitable item or item is Nothing, result will be an empty list. Otherwise function recurses, computes tail starting from selected element and constructs chain starting by selected item and followed by tail.

join item at the start of case analysis collapses two nested Maybes together:

Nothing will result Nothing (no suitable continuation) Just Nothing will also result Nothing (end of chain reached) Just a will result Just a (suitable element found)

In the end we have list that is sort of like: h : chooseM (candidates config h) : chooseM (candidates config h') : chooseM (candidates config h'') : ... : []


For convenience we define two other functions. First one is for when we don’t want to use Rand g a. It’s done by applying runRand function with our chainM function, config and RandomGen.

chain :: (Ord a, RandomGen g) => Config a -> g -> ([a], g) chain config g = runRand (chainM config) g

More interesting is chains which builds infinite list of chains:

chains :: (Ord a, RandomGen g) => Config a -> g -> [[a]] chains config g = c : chains config g' where (c, g') = chain config g

This uses chain function to create starting element (which is markov chain) and new generator g'. Then it builds a list where that first chain is followed by list of chains that is created by calling chains with that new random generator. Since there’s no termination case in the function, it will compute infinitely long list of markov chains. This works because elements are computed only when needed. For all intents and purposes for program using this infinite list, items are there when needed.


Hardest part working with markov chains (at least in my opinion) is building suitable configuration. When you have that configuration at hand, building chains from it requires relatively small amount of code. In the next episode we’re going to use this chains for our space game.

Questions, comments and feedback are always welcome. Best way to reach me is by email or in fediverse where I’m tuturto@mastodon.social.

HPR2927: Stardrifter RPG Playtest Part 09

Oct 22, 2019


This episode is Part 9 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this part, the characters agree to join someone else’s treasure hunt, with the success (or failure) of their own mission in the balance!

Special thanks to my playtesters: Thaj, Mark (who was playing Brinn), and X1101!

HPR2926: Full Circle Magazine

Oct 21, 2019


Hi Everyone in HPR land this is Tony Hughes coming to you from Studio B at Woodbrooke Quaker Study Centre in Birmingham in the UK, where I am currently staying for a week of voluntary work.

The reason for this short episode is to talk about a community magazine that I have been reading since I started to use Ubuntu Linux back in 2007. Full Circle magazine actually produced a pilot issue in April of 2007 and issue one was issued in June 2007. All issues are published as a free pdf download and all the content is under a Creative Commons licence.

Free Circle Magazine initially started as an Ubuntu (and official spins of Ubuntu) magazine but over the years while still being officially about Ubuntu or Linux Distributions based on Ubuntu, many of the articles are applicable to those across the Linux community.

Over the years, as well as printing one off articles about individuals’ journey to using Linux, reviews and letters from readers, there have been regular series on topics such as Inkscape, Python programming, Open/LibreOffice, Virtualisation and much more.

Sadly after over 12 years of producing a regular monthly magazine for the Linux community some of the regular article series are coming to an end and due to ill health at least one regular writer is not able to contribute at the moment, and this is leaving the magazine short of content and in danger of possibly coming to an end.

As a podcast community that is used to the idea of crowd sourced content, many of whom are also Linux users, could I ask that some of you that have read Full Circle, but never contributed, consider sending in some content. It could be an article on how you started using Linux, about some Linux software that you think the readers may be interested in learning more about, or just a letter to Ronnie to say thanks for all his efforts putting out a magazine every month for the last 12+ years.

Like many things we often don’t miss them until they are gone, and I would hate to think that Full Circle Magazine is one of those things that I will miss in the future. I have put my money where my mouth is and in coming issues you may see me in print, talking about podcasting. You could even use any writing you do as the base for a HPR show, and achieve two goals in one go.

All the best for now.

Links https://www.woodbrooke.org.uk/ https://fullcirclemagazine.org/ https://fullcirclemagazine.org/issue-149/

HPR2925: LinuxLugCast's Memorial for FiftyOneFifty

Oct 18, 2019


LinuxLugCast Memorial

We are here tonight to share memories of our friend Donald Grier aka FiftyOneFifty

Fifty was involved with many podcast over the years

Obviously LinuxLugCast http://www.linuxlugcast.com https://archive.org/search.php?query=linuxlugcast Hacker Public Radio http://hackerpublicradio.org/ http://hackerpublicradio.org/correspondents.php?hostid=131 /dev/random http://devrandomshow.org/ http://devrandomshow.org/shows/?f=all.html Kernal Panic Oggcast https://archive.org/search.php?query=KernelPanic+Oggcast&page=2

Shared thoughts and memories:
Ken Fallon

I was in the back room pottering away when espeak notified me that 5150
had passed away. I went back to the computer and read the announcement
in the IRC Logs and confirmed the news. Some dude I had never met, never
seen in my life, and didn’t even know his real name, was gone and I was
in the back room crying my eyes out.

Crying for the loss of a friend.

When had he become a friend ?

People have been socializing since the dawn of humans, be it at the camp
fire, the forge, pub, hairdresser, sports club, church, or wherever.

For us it was via Linux podcasting. You are there because you share a
common interest. If you were into Linux podcasting then you could not
help but get to know fiftyonefifty. The guy turned up everywhere if not
on the podcasts themselves he was commenting on them. I have 619
messages from him about HPR alone.

He submitted his first show back in 2010 and has been a regular since
then. At some point after that I knew that he was on my “special list”
of people who I could rely upon to fill the queue if needed.

And as I sat there crying I realized that he had also sneaked onto my
list of friends.

I’ve not always been a fan of the New Year Show, but now I am glad for
it. While I may never get to share a beer with him any more, or take him
up on his promise to let me fire off some rounds on his farm, I did at
least get to shoot the breeze with him for many a happy hour.

Goodbye old friend you will be missed

A Ramble for FiftyOneFifty: King of Ramblers

I am writing a Ramble for a man I knew only as FiftyOneFifty.  I never knew his real name,
nor do I know if he knew mine.  In many things, Names do not matter, People, Actions, and
feeling do.   We podcasted together off and on, over several years.  I don’t recall exactly
how many.   It doesn’t matter now, since they are all that there will ever be.  We grew to be
good friends.  I never met him in person, online life is like that.  I only know my life would be
much poorer, if I had not known him.  Hearing he died, shattered me.  This Ramble is my try
at putting most the pieces back in place.  Of course, nothing can replace the largest piece,
the Man Himself.  My heart and prayers go out to those friends and family dealing with his loss.

His death is a harsh, unchangeable, fact.  I shall focus on his life, and things better remembered
than the wall we all will hit one day.  Fifty was a man if Life, Joy, and passions.  That is how I shall
write of him.  I had a far too short time, to learn about him, and from him.  It will also  warm my heart,
where he live yet, and has for a long time.  I learned this fact, only after I could no longer talk with him.

I found him easy to talk with, and listen to.  He was also “Vaccinated with a Victrola Needle ”  as
my relatives might say.  He could ramble on for hours. enjoyably.  He virtually always made sense,
even when in his cups.  He shared himself, his hobbies, experience, and his travels with us, on our
podcasts.  While he went to Linux events, he never limited himself to just linux topics.  He reported the
non Linux features of events.  This great for choosing family trips to them.   He included accommodations, restaurants, and pubs in the area.  I don’t travel, or drive, so these second hand visit were a delight.

His research and Linux activities made up much of his contribution to our podcasts.  He life also
flowed in, to entertain and inform us.  He lived in the country, farming, cows, trouble getting Internet
service were included.  My parents can off farms, so he even kept my ties to that life alive.  Firearms, cars, especially his beloved Hearse were shared interests.  tale from his tech support work, for businesses and schools enlightened me.  Farmers are natural pack rats, so gathering all sorts of discarded computer gear was natural.   Unfortunately he lost most of it in the fire which destroyed his house.   Losing his house, and even his dear father, never seemed to blight his spirit or life, in the long run.  It would be natural to keep such private matters from more distant friends, as I was.  Nor did his long illness color the side of him I saw.  it got in his way, sometimes,  as I recall, but never in his spirit.  I wish I had been closer, to offer myself more to the man I miss dearly.  I must just try to use his independent example, in my own life.  Anyone could do much, worse.   His quiet touch helped heal me in ways I am only now realizing.

I started the day in tears, still aching from losing a rare, true friend.  Then I recalled a song from Toby Keith, called “Cryin’ for Me (Wayman’s Song ) written about he loss of his close friend, Wayman Tisdale.  Toby found about his friends passing on Friday.  On Sunday Toby was driven to write the memorial song.  In it he says his tears are not for his lost friend, who is now in Heaven, but for Toby himself, and all those family, and friends, Wayman left behind.  I believe Fifty is in Heaven, with his Dad, and those who have gone before.  He will see things from the Good Seats.  He can enjoy all the Holidays, and never feel the cold.  I was driven to write like Toby, to handle my own shock and grief.  We Cry and Mourn, those left behind in the Mortal world, for our loss and pain.  Our dear One is beyond pain, perhaps for the first time in years.  He has earned his time in Grace.  He as paid as we pay now, for life beyond grief, with those who have gone ahead.   I hope my words and memories may help  the ones he left behind.  Pain is a Mortal thing. It need not be deadly, or poisonous.  Fifty’s Life is a great example of this and many other things.  I hope we can go forward, with his example helping heal our loss of him.    God Bless You, Fifty, and those you touched in turn.

HPR2924: Hacking an Alarm Clock to Make it Quieter

Oct 17, 2019


The alarm clock on my bedside table had a very loud alarm—so loud that it scared me and made my heart race when it went off. I know you're thinking I should just use an alarm on my phone, but for whatever reason I wanted to use the alarm clock. In this episode I talk about installing a resistor in the speaker wires of the alarm clock so that it won't be so loud when it goes off. It's all good now. Loud enough to wake me up, but not so loud that it scares everyone.

Alarm Clock Hack

HPR2923: Describing how I listen to podcasts PART 5

Oct 16, 2019


Below are examples of messages shown on the screen during operation

System Up (Unfortunately I didn’t get a picture of this message)

Picture 01
Shows the unit waiting to get a wi-fi connection and get given an IP address.

Picture 02
Unit goes to the HPR site and gets the number of days to free slot in the show queue. At the time when I took the picture the queue had a healthy 22 shows!

Links to three previous shows I did that mention the Blinkstick

Solving a problem I had with my Blinkstick

Tracking the HPR queue using python and a Blinkstick

Follow on to HPR2340 (Tracking the HPR queue in Python)

Link to Moc, Music On Console

Picture 03 Picture 04
Menu 0 Podcasts screens

0 [PODCASTS] 0 1 <|| PLAY/PAUSE (Toggles moc between play and Pause) 0 2 << INFORMATION(Displays information about the current track) 0 3 << (Move to previous track in playlist) 0 4 << (Move to next track in playlist) 0 5 LIGHT (Toggle back-light on LCD screen) PUSH IN TOP TOGGLE BUTTON (Seek forward or back in current track)

Picture 05 Picture 06
Menu 1 Audiobooks screens

1 [AUDIOBOOKS] 1 1 <|| PLAY/PAUSE (Toggles moc between play and Pause) 1 2 << INFORMATION(Displays information about the current track) 1 3 << (Move to previous track in playlist) 1 4 << (Move to next track in playlist) 1 5 LIGHT (Toggle back-light on LCD screen) PUSH IN TOP TOGGLE BUTTON (Seek forward or back in current track)

Picture 07 Picture 08
Menu 2 System screens

2 [SYSTEM] 2 1 Sys Information (System information) 2 2 WiFi (Displays WiFi inofrmation such SSID & signal strength) 2 3 HPR (Displays the number days to the next free slots on FPR que) 2 4 Not shown, (Not in use) 2 5 LIGHT (Toggle back-light on LCD screen) PUSH IN TOP TOGGLE BUTTON (Shut-down the Raspberry Pi)

Infra-red Sensor

Example of my Samsung TV remote control

Lirc Article from Wikipedia

Picture 09
Infra-red sensor turned on

Picture 10
Infra-red sensor turned off

Kodi article on Wikipedia, (Formerly XBMC)

Picture 11
Picture 12
Example of a message being sent to the unit telling me that a backup is complete. The bright pink LED on the Blinkstick lets me know at a glance that a message has been sent to the display.

EEE PC article on Wikipedia

Switch Bounce article on Wikipedia

Picture 13
Picture 14
Picture 15
A flavour of what information is shown when the information button 2 is pushed. The picture showing the title scrolling from right to left was blurred so I didn’t include this.

Picture 16
The menu displayed during seek, this in initiated by pushing and releasing the toggle button while either in the Podcasts main menu 0 or Audio book main menu 1.

Picture 17
The shut-down menu this in initiated by pushing and releasing the toggle button while in the System main menu 2.

HPR2922: Stardrifter RPG Playtest Part 08

Oct 15, 2019


This episode is Part 8 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this part, the characters reevaluate their life choices, and decide that negotiation is the better part of valor!

Special thanks to my playtesters: Thaj, Mark (who was playing Brinn), and X1101!

HPR2921: Geocaching with the family

Oct 14, 2019


In this episode, Dave and his family wander the paths of Sandall Beat Wood in Doncaster to participate in the game of Geocaching. During this time, which demonstrates an unusual level of failure in us playing the game, we try and explain what the game is all about.

No, not The Game...

As I explain at the beginning of the episode, this is a fairly long episode which hasn't been edited down much, so there are a lot of ambient pauses and heavy breathing to be enjoyed.

Recorded in the field on my Olympus DM-3 voice recorder.

Caches explored Cache 1 - GC7F8ND - not found Cache 2 - GC50TVW - not found Cache 3 - GC7KRHH - found! Links Link to photos and screenshot geocaching.com Official Geocaching App: Google Play | App Store c:geo Geocaching app: Google Play

HPR2920: Better Social Media 03 - MeWe

Oct 11, 2019


MeWe is another platform that was advertised to users left high-and-dry by the closure of Google Plus. It is not federated, but does make strong claims of privacy protection, and is the slickest alternative I have seen to Google Plus. So when Google Plus disappeared, many people moved over to this platform. https://www.zwilnik.com/?page_id=1030

Links: https://mewe.com/ https://mewepro.com/ https://mewe.com/store https://mewe.com/# https://www.zwilnik.com/?page_id=1030

HPR2919: hosting software in HPR show notes

Oct 10, 2019


#!/usr/bin/env python import urllib.request import json import re import subprocess # see https://www.weather.gov/documentation/services-web-api #where are we? GPS coordinates lat = 39.275235 lon = -120.9199507 #what is the user agent string? agent = "Jezra's fun lil script" #minimum wind speed in mph? min_speed = 9 def get_api_data(endpoint): print(endpoint) #prepare the connection with custom headers request = urllib.request.Request(endpoint, headers={"User-Agent":agent}) #create a handler for the request handler = urllib.request.urlopen(request) #get the text text = handler.read() #parse the json text to a python object obj = json.loads(text) return obj def wind_is_good(s): #use regex to find the matches matches = re.findall("[0-9]+",s) for match in matches: #convert string to int m = int(match) #is the speed good? if(m>=min_speed): return True #if we get here, there is no match :( return False start_url = "https://api.weather.gov/points/{0},{1}".format(lat,lon) #get the json response from the start_url as a python object obj = get_api_data(start_url) #get the forecast url from the returned data forecast_url = obj['properties']['forecast'] # process the forecast url forecast = get_api_data(forecast_url) #loop through the forcast periods for period in forecast['properties']['periods']: #put name and windspeed into easier to handle variable names name= period['name'] wind = period['windSpeed'] print (name, wind) #check the wind speed if wind_is_good(wind): subprocess.call(["textjezra","{0}: {1}".format(name,wind)])

HPR2918: Selecting random item from weighted list

Oct 9, 2019



We’re going to have a look how to select random item from weighted list. There isn’t that much code this time, but it certainly took many tries to get it working and looking nice.


Imagine stack of building blocks of different heights stacked on top of each other. Height of the each block is chance of how often it will be selected. Selection is done by chopping a stick so that its length at maximum is height of the stack. Place stick next to the stack and select the block that stick reaches at.

Explanation of algorithm

We have list of items and associated weight, defined as Frequency a = Frequency Int a.

Total is sum of all the weights and we select a random number n between 1 and total.

pick function has signature of [Frequency a] -> n -> Maybe a. Empty list will result Nothing. When picking item, if n is equal or less than weight of the first item, return that item. Otherwise, drop the first item, subtract weight of that first item from n and try again. Eventually we either arrive to item which weight is greater than n or to empty list.

Quick detour on random number generators

Haskell functions are pure, meaning that with same input, you are guaranteed to get the same output (safe for some specific cases). Which makes concept of random numbers at first glance to be impossible. This is solved by passing in a random number generator, which can supply you a random value a new random number generator. Using this new random number generator to generate a value yields you a yet another value and yet another random number generator.

Passing these random number generators around in code gets tedious, but there’s different solution: MonadRandom. Using it will thread along generators automatically behind the scenes, ensuring that you always have access to a fresh generator. There’s several functions that can be used to generate random values, but we’re using this one: getRandomR :: Random a => (a, a) -> m a. Given a lower and upper bound, it will return you a random value wrapped in context that carries that new random number generator.

In the end, we need to take our computation (that can be complex and use multiple calls to random number generator) and turn that m a into a. This is done with runRand :: RandomGen g => Rand g a -> g -> (a, g). We give it our computation and a RandomGen g that can generate random values and receive (a, g) where a is our result and g new random number generator. In cases where we aren’t going to use the new generator, we can use evalRand :: RandomGen g => Rand g a -> g -> a, which discards it and returns just a.

Actual implementation with explanation

First, Frequency for expressing weight of individual item. It’s parametrized, so can be used with any data.

data Frequency a = Frequency Int a deriving (Show, Read, Eq)

Next, determining which item to choose, based on stack and measuring stick. In case a value outside of valid range has been selected, we end up with Nothing, otherwise with Just a. First case is for empty list (either we called this originally with empty list or picked number that is greater than total sum of weights), second one either picks the first item of list or recursive calls itself removing first item.

pick :: [Frequency a] -> Int -> Maybe a pick [] _ = Nothing pick (Frequency x item:xs) i | i <= x = Just item | otherwise = pick xs (i - x)

Finally, function for calculating total of weights and choosing random number. We’re using that Rand g (Maybe a) I explained earlier. First case is for empty list again and latter case for list with at least one item.

choose :: RandomGen g => [Frequency a] -> Rand g (Maybe a) choose [] = return Nothing choose items = do let total = sum $ fmap (\(Frequency x _) -> x) items n <- getRandomR (1, total) return $ pick items n

Notice how we can get random number by n <- getRandomR (1, total), without talking about generators. MonadRandom is handling generators and making sure that there’s always a fresh generator available and new generator is stored ready to be used.

And that’s all the code this time (I told the amount of code is small this time).

In closing

This probably sounds a lot more complicated than it actually is. I arrived to the result after quite many detours, but the end result looks pretty nice.

Next time we’re going to have a look where to use our choose function.

In the meantime, questions, comments and feedback are welcomed. Best way to reach me is email or fediverse where I’m tuturto@mastodon.social. Or even better, record your own Hacker Public Radio episode.

HPR2917: Stardrifter RPG Playtest Part 07

Oct 8, 2019


This episode is Part 7 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this part, the characters make some new friends who show them their guns! Bonus Fun: I make tons of mistakes reading my own rules!

Special thanks to my playtesters: Thaj, Mark (who was playing Brinn), and X1101!

HPR2916: HPR Community News for September 2019

Oct 7, 2019


table td.shrink { white-space:nowrap } New hosts

There were no new hosts this month.

Last Month's Shows Id Day Date Title Host 2891 Mon 2019-09-02 HPR Community News for August 2019 HPR Volunteers 2892 Tue 2019-09-03 Stardrifter RPG Playtest Part 02 lostnbronx 2893 Wed 2019-09-04 Whats in the box! Part 2 NYbill 2894 Thu 2019-09-05 Repairing a Musical Instrument Case Jon Kulp 2895 Fri 2019-09-06 The work of fire fighters, part 2 Jeroen Baten 2896 Mon 2019-09-09 Orange PI Zero LTS version JWP 2897 Tue 2019-09-10 Stardrifter RPG Playtest Part 03 lostnbronx 2898 Wed 2019-09-11 Modeling people in space game tuturto 2899 Thu 2019-09-12 Endeavour OS Tony Hughes AKA TonyH1212 2900 Fri 2019-09-13 Better Social Media 01 - Introduction Ahuka 2901 Mon 2019-09-16 Describing how I listen to podcasts PART 3 MrX 2902 Tue 2019-09-17 Stardrifter RPG Playtest Part 04 lostnbronx 2903 Wed 2019-09-18 What is PMEM JWP 2904 Thu 2019-09-19 DIY URL shortening klaatu 2905 Fri 2019-09-20 Two HPR hosts living in the same region finally meet up! Dave Morriss 2906 Mon 2019-09-23 Feature Engineering for Data-Driven Decision Making b-yeezi 2907 Tue 2019-09-24 Stardrifter RPG Playtest Part 05 lostnbronx 2908 Wed 2019-09-25 Modeling opinions in space game tuturto 2909 Thu 2019-09-26 ONICS Basics Part 3: Networking Fundamentals Gabriel Evenfire 2910 Fri 2019-09-27 Better Social Media 02 - Pluspora Ahuka 2911 Mon 2019-09-30 my internet connection Jezra Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 17 comments in total.

Past shows

There are 3 comments on 3 previous shows:

hpr1328 (2013-09-04) "A Hacker's Perspective On Schizophrenia " by sigflup. Comment 6: Vegewurst on 2019-09-06: "Insightful"
hpr2844 (2019-06-27) "The Sony TC-222-A Portable Reel-To-Reel Tape Recorder" by Jon Kulp. Comment 1: Michael on 2019-09-29: "Muffled sound because of low path filtering."
hpr2881 (2019-08-19) "Automatically split album into tracks in Audacity" by Ken Fallon. Comment 2: Hipstre on 2019-09-01: "2881 - Audacity: Split Album into Tracks"
This month's shows

There are 14 comments on 9 of this month's shows:

hpr2891 (2019-09-02) "HPR Community News for August 2019" by HPR Volunteers. Comment 1: Ken Fallon on 2019-09-02: "Where was Ken ?"Comment 2: Jon Kulp on 2019-09-03: "Heroic effort!"Comment 3: Dave Morriss on 2019-09-04: "Thanks Jon"
hpr2893 (2019-09-04) "Whats in the box! Part 2" by NYbill. Comment 1: timttmy on 2019-09-05: "Trem pedal"Comment 2: Jon Kulp on 2019-09-06: "No delay"Comment 3: NYbill on 2019-09-07: "Hit and Miss"
hpr2895 (2019-09-06) "The work of fire fighters, part 2" by Jeroen Baten. Comment 1: Ken Fallon on 2019-09-06: "Very dissapointed"Comment 2: Steve on 2019-09-10: "Volunteer Firefighters"
hpr2903 (2019-09-18) "What is PMEM" by JWP. Comment 1: archer72 on 2019-09-27: "Awesome"
hpr2904 (2019-09-19) "DIY URL shortening" by klaatu. Comment 1: tuturto on 2019-09-23: "clever"
hpr2906 (2019-09-23) "Feature Engineering for Data-Driven Decision Making" by b-yeezi. Comment 1: archer72 on 2019-09-27: "Nice show"
hpr2907 (2019-09-24) "Stardrifter RPG Playtest Part 05" by lostnbronx. Comment 1: archer72 on 2019-09-27: "Nice series"
hpr2909 (2019-09-26) "ONICS Basics Part 3: Networking Fundamentals" by Gabriel Evenfire. Comment 1: archer72 on 2019-09-27: "Interesting"
hpr2910 (2019-09-27) "Better Social Media 02 - Pluspora" by Ahuka. Comment 1: archer72 on 2019-09-27: "Nice show"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-September/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Tags and Summaries

Thanks to the following contributor for sending in updates in the past month: windigo

Over the period tags and/or summaries have been added to 1 show which was without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

Change to the Missing Tags document

The section of this document which lists all of the tags currently in the system has been made more accessible. If you know of a tag in the system and you want to find out how many instances there are and which shows use them you can construct a query of the form:


This would look for the tag 'vim' and position the page at the relevant place.

If the tag you are looking for contains spaces, you need to replace them with underscores. So to look for the tag 'vietnamese stringed instruments' your query would have to be:


HPR2915: Intro - My Recording Setup

Oct 4, 2019


I discuss loading Fedora on various bits of older hardware and devise a plan to turn one of those bits of older hardware into a dedicated headless audio processor using its firewire port to keep yet another older piece of hardware alive: a Yamaha GO46 audio interface.

Having done that and finding that it all performs admirably, I illogically decide to replace it with newer (but not new) hardware and buy yet another different model firewire audio interface: a Focusrite Saffire Pro 24.

I record the end of the show on audio interface #3: a USB based Steinberg UR22mkII, which one could argue that I should have been using all along, leaving the firewire gear in the last decade where it belongs (?).

HPR2914: Describing how I listen to podcasts PART 4

Oct 3, 2019


PiFace Control and Display

How to fit, setup and install the required software for your Raspberry Pi running the Raspbian Operating system

Pictures 01, 02 and 03 show how the PiFace Control and Display board and raspberry pi fit into the case

Pictures 04 and 05 shows the piece of plastic used to transfer the light from the LED’s on the Pi board to the holes in the casing. This is supposed to allow you to monitor the PI LED’s. I held it in place using a piece of Blu Tack.

Wikipedia article about Blu Tack

Picture 6 shows the completed box

Pictures 7 and 8 show the project in operation and mounted on a spare Anker tablet stand that I had lying about.

This is an example of the Anker stand I used. I use it to hold my project at a 45 degree angle so I can see it from around the room, it is intended to be used as a tablet stand.
Anker stand for my Nexus 7, pictures, links

HPR2913: Windows, SDN, and Firewalls

Oct 2, 2019


Intro Last Upload was hpr1468 March 19, 2014 python >>> print (D.today() - D(2014, 3, 19)).days 1999 >>> 2000/365 5


In the last 5 years:

Traveled the world. Deployed a lot of things for work. Taken on a new role which moves me from Datacenters to Networks. Learned a lot about Operations, Datacenter Infrastructure, People around the world, and why it is important to have your house in order. Read over 3 dozen books. Paid off debt and focused on long term financial goals. Humility, Humanity, and Harmony: Three things I have continued to strive for in my personal life, work, and hobbies.

Let's Start The Show off in the wrong direction

Windows Chocolatey Great Tool for Downloading free software from the windows powershell command line https://chocolatey.org/docs/installation Sublime Text 3 Fantastic Text editor and very powerful. I use this to quickly parse data using regex searches and push this to spreadsheets or other tools that allow me to organize data quickly. Overall Great tool for anyone Summary: Overall: The importance of being an everyday Windows User has allowed me to focus on solving problems in different and unique ways. I've found that the way I use Windows is not the same as most normal Windows Users. I live most of the time inside of Chrome so Windows is just another OS to get my Chrome Browser running. Observation: Windows has definitely matured over the past 10 years. I find myself enjoying the time I save using Windows 10. Contradictions: I still use Linux, but as a VM to work on things that I just can't do inside of Windows. Web Stuff Regex Test and debug your regex. It is a great tool that combines pastebin and regex debugging. This allows you to share your regex with other by simply using a link. There is a lot of useful information on the site about what each portion of your regex is doing. https://regex101.com Maps USGS Maps Very nice site that allows you to download PDFs of 1:24000 or 7.5 minute Maps. You can print these off and use a Map grid tool to navigate your journey. This is kind of an analog tool but you are downloading the maps to your computer or phone. Good to have maps saved offline while you hike, that way you don't get lost. https://store.usgs.gov/map-locator SDN Information If you're just starting with Software Defined Networking or are already working with it in a production environment, there is much to learn but very few places to find aggregated information. The GitHub Page called awesome-sdn has tons of links on NOS,Controllers, Libraries, and more. I have A couple of Northbound network and Aruba switches at home to use with my SDN projects. I highly recommend you start getting familiar with network automation using ansible or other automation best practices at the least. For the more technical stuff definitely start looking at SDN. Awesome-SDN https://github.com/sdnds-tw/awesome-sdn/blob/master/README.md Northbound Networks SDN Devices https://northboundnetworks.com/ ZeroTier is an example of SDN WAN or Edge Networking https://www.zerotier.com/download/ Home Hacks Home Phone Cheap way to have a home phone Google Voice Number OBi200 VoIP Telephone Adapter 100Mb LAN Has the Option to sign up for 911 but with just Google Voice Number it is a free way to have a house phone https://www.obitalk.com/info/products/obi200 Firewalls Off the shelf vs DIY options Off The Shelf Ubiquiti Option Ubiquiti "SDN" Like FW decent enough for homes with 100Mb/s Uplinks but not for homes with 1Gb/s uplinks. USG3 can't handle IPS throughput past 50Mb/s USG3 can't handle FW PPS past 400Mb/s at 100B packets, which is around 500,000 PPS The Ubiquiti alternative would be to spend money on an XG which is well over $1000 USD. DIY Option The best alternative would be to purchase a used SFF PC with at least 1 Gb onboard NIC and 2 PCIe x16 or x 8 lanes. This would allow for 10Gb NIC options 4x10Gb Intel Nics are a steal or 4 x 1Gb Nics which are an even better deal. Going SFP+ is a great option because you can use Copper or Fiber Modules in the same NIC card. Summary The most important part about the SFF Option, you get to use a xeon processor, at least 32 GBs of RAM, and install up to 4 HDDs in the System. You can even install a PCIe NVME or M.2 Sata using a PCIe peripheral. For software, PFSense or Sophos XG will be great options. If you really want to get technical, load up a hypervisor and then install the Firewall as a VM. This would allow you to leverage the SFF system for more than just a FW and allow for easy testing of other types of FW solutions. Hardware Info Intel X722DA4FH Ethernet Network Adapter X722-DA4 https://g.co/kgs/j9aNJz HP Z240 SFF https://g.co/kgs/ax2hwq Firewall OSes PFSense https://www.pfsense.org/ Sophos https://www.sophos.com/en-us/products/next-gen-firewall.aspx OPNSense https://opnsense.org/

HPR2912: Stardrifter RPG Playtest Part 06

Oct 1, 2019


This episode is Part 6 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes. The remaining episodes in this mini-series, including this one, were all from the second session.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this part, the characters fly out to the derelict (though hardly empty) spaceship, and find a way to sneak aboard.

Special thanks to my playtesters: Thaj, Mark (who was playing Brinn), and X1101!

HPR2911: my internet connection

Sep 30, 2019


Any notes for this episode should probably contain links to the ISPs mentioned in the show. Since I do not wish to harm any listeners, I have opted to not include links to evil ISPs.

HPR2910: Better Social Media 02 - Pluspora

Sep 27, 2019


Pluspora is an instance of the Diaspora software that was specifically designed to appeal to users of Google Plus. So when Google Plus disappeared, many people moved over to this platform. https://www.zwilnik.com/?page_id=1027

Links: https://pluspora.com/ https://en.wikipedia.org/wiki/GNU_General_Public_License https://diasporafoundation.org/formatting https://en.wikipedia.org/wiki/Markdown https://www.zwilnik.com/?page_id=1027

HPR2909: ONICS Basics Part 3: Networking Fundamentals

Sep 26, 2019



In this episode I decided to take a slight diversion into networking fundamentals. As before, if you want to learn more about installing the ONICS tool suite, go back and listen to HPR 2882.

There are three key concepts to understand about modern networks. They are:

digital - the networks carry bits and bytes (binary digits)

packet switched - devices break data into blobs of data called "packets" and take turns sending and receiving those packets to/from other devices attached to the network

internetworked -- machines communicate using a protocol that allows traffic to traverse across multiple, independently-managed networks in a uniform way

My Setup

2 laptops connected to a home wifi network that has Internet connectivity.

Practicing sending data from a source machine to a destination machine. Both are running Linux.

Source machine:

Wifi interface: wlan0 Ethernet address: 00:22:fa:a7:69:90 IP address:

Destination machine

Wifi interface: wlo1 Ethernet address: 6c:88:14:7c:2e:14 IP address:

Internet Router:

Ethernet address: 00:0d:b9:23:f2:51 IP address: More Terminology

Address - a number that identifies a machine's interface in a network

Packet - a blob of binary data sent as a unit over a network

Route - a rule that specifies how to forward traffic to a given address

Router / Gateway - a machine that uses the IP protocol and forwards traffic between multiple networks that it connects to

Network Protocol - a set of rules and data formats for exchanging information over a network

Standard UNIX Commands ifconfig (no arguments or '-a') list interfaces on a machine ifconfig IFNAME list properites about a given interface ping -c 1 IPADDRESS send an echo request to machine IPADDRESS arp -na Dump the Ethernet addresses of known nearby machines netstat -nr Dump the routes in a system netstat -nr | grep "^" Find the route (and thus IP address) of the default gateway ONICS Commands in this Episode

rawpkt - take a blob of data and wrap it in an XPKT format (so other ONICS tools can understand what it is)

ethwrap - take an XPKT and prepend an Ethernet header to it

ipwrap - take an XPKT and prepend an IP header to it

pktin - read a stream of packets from a network interface

pflt - filter a stream of packets so that only those matching a pattern get through

pktout - send a stream of packets to a network interface

x2hpkt - convert XPKTs into a hex dump

xpktdump - like x2hpkt, but send the output to a pager like 'less' for easy reading

Sending an Ethernet Packet to the Destination On the receiver: $ sudo pktin wlo1 | pflt "not ip and eth.dst == 6c:88:14:7c:2e:14" | x2hpkt On the sender: $ echo "hello world" | rawpkt | ethwrap "eth.dst = 6c:88:14:7c:2e:14; " "eth.src = 00:22:fa:a7:69:90; " "eth.ethtype = 12;" | sudo pktout wlan0

Note that while I broke up the field setting commands into multiple lines in ethwrap, they can all be part of a single quoted string if desired. To store the packet to a file rather than send it instead do something

$ echo ... | rawpkt | ethwrap ... > outfile.xpkt

One can then dump the packet by running:

$ xpktdump outfile.xpkt

or send the packet by running:

$ sudo pktout outfile.xpkt wlan0 Sending an IP Packet to the Destination over the Local Network On the reciever: $ sudo pktin wlo1 | pflt "ip and ip.proto == 255" | x2hpkt On the sender: $ echo "hello world" | rawpkt | ipwrap "ip.saddr =;" "ip.daddr =;" "ip.len = 32;" "ip.ttl = 64;" "ip.proto = 255;" | ethwrap "eth.dst = 6c:88:14:7c:2e:14; " "eth.src = 00:22:fa:a7:69:90; " "eth.ethtype = 0x800;" | sudo pktout wlan0

Note that while I broke up the field setting commands into multiple lines in ipwrap and ethwrap, they can all be part of a single quoted string if desired. Also note that it is not actually necessary to set the 'ip.len' and 'eth.ethtype' fields: the tools will do that automatically.

Sending an IP Packet to the Destination via IP On the receiver: $ sudo pktin wlo1 | pflt "ip and ip.proto == 255" | x2hpkt One the sender: $ echo "hello world" | rawpkt | ipwrap "ip.saddr =;" "ip.daddr =;" "ip.ttl = 64;" "ip.proto = 255;" | ethwrap "eth.dst = 00:0d:b9:23:f2:51; " "eth.src = 00:22:fa:a7:69:90; " | sudo pktout wlan0 Challenge

There are several differences between the packets that arrive at the destination machine when sending directly over the local network versus sending via an IP gateway (router). I've mentioned how the Ethernet header is different. Can you find the other differences? What causes these differences?

TIP: instead of sending the pktin command to x2hpkt, send it to a file. Do this for both local network send and for sending via the router saving each to different files. Then run pdiff on the two files to highlight the differences.

HPR2908: Modeling opinions in space game

Sep 25, 2019


We continue with people, this time focusing on opinions. This episode has somewhat more code than previous one, so following along with the shownotes might be a good idea. I’m trying to minimize amount of code I read out aloud.


One person’s opinion of another is expressed as OpinionScore that ranges from -100 to 100.

Computing the score is based on intelligence player has available to them. Internally we have ReportResult that tracks score, reasons for the score and confidence level about the results. It’s defined as:

data ReportResult = FeelingLevel OpinionScore | ReasonsLevel OpinionScore [OpinionReason] | DetailedLevel OpinionScore [OpinionReason] deriving (Show, Read, Eq)

We’re going to be adding up these results quite a bit, so we define SemiGroup and Monoid instances for it. When two results are combined, scores are added together, lists of reasons are concatenated and the lowest confidence level is used. This is written as:

instance Semigroup ReportResult where (FeelingLevel s1) <> (FeelingLevel s2) = FeelingLevel (s1 <> s2) (FeelingLevel s1) <> (ReasonsLevel s2 _) = FeelingLevel (s1 <> s2) (FeelingLevel s1) <> (DetailedLevel s2 _) = FeelingLevel (s1 <> s2) (ReasonsLevel s1 _) <> (FeelingLevel s2) = FeelingLevel (s1 <> s2) (ReasonsLevel s1 r1) <> (ReasonsLevel s2 r2) = ReasonsLevel (s1 <> s2) (r1 <> r2) (ReasonsLevel s1 r1) <> (DetailedLevel s2 r2) = ReasonsLevel (s1 <> s2) (r1 <> r2) (DetailedLevel s1 _) <> (FeelingLevel s2) = FeelingLevel (s1 <> s2) (DetailedLevel s1 r1) <> (ReasonsLevel s2 r2) = ReasonsLevel (s1 <> s2) (r1 <> r2) (DetailedLevel s1 r1) <> (DetailedLevel s2 r2) = DetailedLevel (s1 <> s2) (r1 <> r2) instance Monoid ReportResult where mempty = DetailedLevel mempty mempty Opinion based on traits

Current system compares two lists of traits. For example, two brave characters like each other slightly better than if one of them would be coward. Comparison is done by traitPairOpinion function, which definition I’m omitting as it’s rather long and not too interesting. It’s signature is: traitPairOpinion :: TraitType -> TraitType -> Maybe (OpinionScore, OpinionReason). So, given two traits, tells how that pair affects to opinion and reasoning for it.

In order to have nicer format for out data, we introduce a helper function:

traitPairScore :: TraitType -> TraitType -> (OpinionScore, [OpinionReason]) traitPairScore a b = case traitPairOpinion a b of Nothing -> mempty Just (s, r) -> (s, [r])

This is because (OpinionScore, OpinionReason) isn’t monoid, but (OpinionScore, [OpinionReason]) is, which means we can combine them with <>.

Actual score calculation based on traits, we do it like this:

traitScore :: [TraitType] -> [PersonIntel] -> [TraitType] -> [PersonIntel] -> ReportResult traitScore originatorTraits originatorIntel targetTraits targetIntel = if (Traits `elem` originatorIntel) && (Traits `elem` targetIntel) then DetailedLevel score reasons else FeelingLevel score where (score, reasons) = mconcat $ traitPairScore <$> originatorTraits <*> targetTraits

The interesting part is mconcat $ traitPairScore <$> originatorTraits <*> targetTraits. Function traitPairScore expects two TraitType values as parameters, but we’re calling it with two lists of such values. First step is to use <$> and list of values, which produces a list of partially applied functions. Second step is to use <*> to call each and every of those functions with values from second list. Result is a list of results that were obtained by calling traitPairScore with every combination of elements from two lists. Final step is to take this list of ReportResult values and combine them to single result with mconcat.

Finally, based on available intel, ReportResult of correct level is created.

Opinion based on relations

Score based on relations is similar, but a bit convoluted (or rather, a lot more).

Intel here has two dimensions. One of them is relationship visibility (is it public, family relation or secret relation), another is level of detail: BaseOpinionIntel, ReasonsForOpinions and DetailedOpinions.

relationScore is the entry point for calculation:

relationScore :: [PersonIntel] -> [Relation] -> ReportResult relationScore intel relations = mconcat $ (relReport oIntel score) <$> visibilities where score = mconcat $ (relationTypeScore . relationType) <$> relations visibilities = mkUniq $ relationVisibility <$> relations oIntel = mkUniq $ mapMaybe (\case Opinions x -> Just x _ -> Nothing) intel

Code has to take into account of what level of intel we have about opinions and on what detail: oIntel. On the other hand, visibilities is unique relation visibilities that exists in relations in this particular case and score is computed based on relations.

Function relReport creates final report. It takes into account on what level of intel we have, by doing: matching = safeHead $ reverse $ sort $ filter (\x -> opinionIntelVisibility x == visibility) intel. This finds highest level intel we have about this particular relationship visibility. Based on the highest level of available intel ReportResult is created with correct confidence level. Ie. if there’s no specific intel, we get FeelingLevel report. If there’s intel about why particular person has certain opinion, we get ReasonsLevel report. Whole definition of function is below:

relReport :: [OpinionIntel] -> (OpinionScore, [OpinionReason]) -> RelationVisibility -> ReportResult relReport intel (score, reasons) visibility = case matching of Nothing -> FeelingLevel score Just (BaseOpinionIntel _) -> FeelingLevel score Just (ReasonsForOpinions _) -> ReasonsLevel score reasons Just (DetailedOpinions _) -> DetailedLevel score reasons where matching = safeHead $ reverse $ sort $ filter (\x -> opinionIntelVisibility x == visibility) intel Opinion report

To pull all this together, we combine results of these two functions. Based on given information, it’ll compute traitsRep and relationsRep. These two are combined with <> as explained earlier in episode:

scores are summed up reason lists are concatenated confidence level is lowest of two opinionReport :: [TraitType] -> [PersonIntel] -> [TraitType] -> [PersonIntel] -> [Relation] -> OpinionReport opinionReport originatorTraits originatorIntel targetTraits targetIntel targetRelations = reportResultToOpinionResult $ traitsRep <> relationsRep where traitsRep = traitScore originatorTraits originatorIntel targetTraits targetIntel relationsRep = relationScore originatorIntel targetRelations

Finally ReportResult is transformed to OpinionReport, which can be sent to client.

OpinionReport has three levels:

BaseOpinionReport only tells if feeling is positive, neutral or negative OpinionReasonReport has feeling and in addition to reasoning DetailedOpinionReport has exact (more or less) score and reasoning data OpinionReport = BaseOpinionReport OpinionFeeling | OpinionReasonReport OpinionFeeling [OpinionReason] | DetailedOpinionReport OpinionScore [OpinionReason] deriving (Show, Read, Eq)

Actual transformation is shown here:

reportResultToOpinionResult :: ReportResult -> OpinionReport reportResultToOpinionResult (FeelingLevel score) = BaseOpinionReport $ scoreFeeling score reportResultToOpinionResult (ReasonsLevel score reasons) = OpinionReasonReport (scoreFeeling score) reasons reportResultToOpinionResult (DetailedLevel score reasons) = DetailedOpinionReport (clamp (-100) 100 score) reasons Note about incorrectness

Reports are based on intel and this might lead into incorrect results. In case of player’s own avatar, they have full intel (ie. they know all relations, all traits and so on.) Therefore opinion about some other person is based wholly on what we know about them.

But in case of gauging somebody else’s opinion about us or person A’s opinion of person B, when A or B isn’t us, there’s chance of misjudging things. We might not know everything about them, or we might know more about A than B knows about them. In short, opinion shown for player, is just best effort guess.

In closing

Questions, comments and feedback is welcome. Even better is if you record your own HPR episode. Best way to reach me nowadays is by email or in fediverse, where I’m tuturto@mastodon.social.

ad astra!

HPR2907: Stardrifter RPG Playtest Part 05

Sep 24, 2019


This episode is Part 5 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this part, the characters take on a contract to deal with some...hippies?

Special thanks to my playtesters: Klaatu, Thaj, and Mark (who was playing Brinn)

HPR2906: Feature Engineering for Data-Driven Decision Making

Sep 23, 2019


Example of the input data Client name Date ordered Client 1 2019-01-01 Client 1 2019-01-01 Client 3 2019-01-01 Client 3 2019-01-01 Example of the engineered features Client name volume last order date first order date days since last order Client 1 292 2019-09-03 2015-03-04 10 Client 2 18 2019-09-09 2019-09-04 4 Client 3 300 2019-08-16 2016-11-15 28 Links Feature Engineering Feature

HPR2905: Two HPR hosts living in the same region finally meet up!

Sep 20, 2019



Two HPR hosts who live in the Edinburgh locality in Scotland met on Saturday 24th August for a chat.

The hosts are:

MrX - first HPR show “Hobbies” on 2012-01-27 Dave Morriss - first HPR show “Useful Vim Plugins” on 2012-10-05

Some of the meeting was recorded and is presented here.

Recording information

We were both recording this chat. Dave was using his Zoom H2n (with the microphones in XY mode) and MrX had left his small Dictaphone-like recorder on the table.

Most of the audio here was from the Zoom, but at one point it switches to MrX’s recorder for comparison. The sample is at about 18 minutes into the recording (hard to judge since an intro sequence will have been added on the HPR site). A “chirp” effect has been added at the start and end of this sample to help with identification.

The Zoom track had noise reduction applied to it, using a noise sample from the start as a reference. The sample from MrX’s recorder also had noise reduction applied, and both tracks were amplified.

Links MrX’s shows that we were talking about: Describing how I listen to podcasts PART 1 Describing how I listen to podcasts PART 2 Describing how I listen to podcasts PART 3 The radio device for the Pi mentioned by Dave: ESP8266 IoT pHAT from Pimoroni (now discontinued) Wikipedia page on the ESP8266 Pimoroni Tutorial on using the pHAT

HPR2904: DIY URL shortening

Sep 19, 2019


Make a directory to house your shortened URLs.

$ ssh example.com mkdir public_html/u

On demand, create a subdirectory for the shortened URL you want to create.

$ ssh example.com mkdir public_html/u/hpr

Create an HTTP redirect in an index.html file.

$ ssh example.com echo ""<html><title>Shortened URL</title><head><meta http-equiv='refresh' content='0; URL=http://hackerpublicradio.org/correspondents.php?hostid=78' /></head></html>"" > www/u/hpr/index.html

Your shortened URL is example.com/u/hpr

HPR2903: What is PMEM

Sep 18, 2019


What is persistent memory?

In brief, PMEM is next generation memory technology whose data transfer speed is as good as DRAM (50-300 ns, 100 times faster than SSDs) and unlike DRAM, it can even retain the data after reboots.

In detail persistent memory (PMEM) is a solid-state high-performance byte-addressable memory device that resides on the memory bus. Being on the memory bus allows PMEM to have DRAM-like access to data, which means that it has nearly the same speed and latency of DRAM and the nonvolatility of NAND flash. NVDIMM (nonvolatile dual in-line memory module) and Intel 3D XPoint DIMMs (also known as Optane DC persistent memory modules) are two examples of persistent memory technologies.

Persistent memory, such as Intel® Optane™ DC Persistent Memory, provides a future-proofed solution. Installed alongside traditional RAM, PMEM has many of the advantages of DRAM, including low latency access. But it comes in greater capacities. Intel® Optane™ DC, for example, will be available in 128GB, 256GB and 512GB sizes.

Persistent Memory Benefits

Persistent memory in the data center allows applications to run without incurring the latency penalty of going out to storage.

The main advantages of persistent memory include:

Provides access latencies less than those of flash SSDs. Increases throughput more than flash storage. Cheaper than DRAM. PMEM is cacheable. This is a huge advantage over PCIe interconnect, which cannot be cached in the CPU. Real-time access to data; allows ultrafast access to large datasets.

Data persists in memory after power interruption, like flash.

Persistent Memory Use Cases Fraud detection Cyberthreat analysis Web-scale personalization Financial trading Internet of Things (IoT) Non \ Volatile /- Non-volatile: you plug it off and on again, and the Information is still there Double \ In-line | DIMM: This the HW format Memory | Module / Persistent Memory Vs. NVRAM

Nonvolatile random-access memory (NVRAM) is random-access memory that retains its information even if there is no power. If power is lost before the data is written to disk, you don’t lose the data because it can be recovered from NVRAM. NVRAM uses battery backup to keep data persistent. During this time it can flash the data out to a flash device that is attached directly. In most cases, NVRAM resides on the PCIe bus.

PMEM or NVDIMM-N can also be backed up by battery. It resides only on the memory bus.

Where PMEM is going

It’s no wonder that this sort of ‘in-memory’ computing has exploded in recent years. According to Gartner, 75 percent of cloud-native application development will use in-memory/PMEM computing by 2019, and by 2021, at least 25 percent of large and global organisations will adopt platforms using in-memory technologies.

Drawbacks of PMEM PMEM is a local store. Host failures can result in loss of availability. In the case of catastrophic errors you may lose all data and must take manual steps to reformat the PMEM. Reference Notes https://www.netapp.com/us/info/what-is-persistent-memory.aspx https://www.intel.co.uk/content/www/uk/en/it-management/cloud-analytic-hub/pmem-next-generation-storage.html http://vthinkbeyondvm.com/vsphere-6-7-what-is-pmem-and-how-vsphere-drs-works-with-pmem-configured-vms/ https://docs.vmware.com/en/VMware-vSphere/6.7/com.vmware.vsphere.resmgmt.doc/GUID-EB72D358-9C2C-4FBD-81A9-A145E155CE31.html https://vmsplice.net/~stefan/nvdimm_slides_public.pdf https://www.theregister.co.uk/2018/09/07/persistent_memory_whirlwind_is_spinning_up/

HPR2902: Stardrifter RPG Playtest Part 04

Sep 17, 2019


This episode is Part 4 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this part, the characters have a job prospect...but is it legitimate, or are they being conned?

Special thanks to my playtesters: Klaatu, Thaj, Mark (who was playing Brinn), and Brian!

HPR2901: Describing how I listen to podcasts PART 3

Sep 16, 2019


In this series I cover how I listen to podcasts and how the process has changed over the years. In this episode I cover the 1st add-on board I purchased for one of my raspberry pi’s I then go on to explain what I do with it.

Raspberry pi

Piface Digital IO, pictures and links
Software Documentation https://piface.github.io/pifacedigitalio/

Command used to install the software & libraries to use the Piface Digital IO board, command from companies website: sudo apt-get install python{,3}-pifacedigitalio

Picture 1
Picture 1, shows the Piface Digital IO board installed on top of my raspberry pi

Picture 2
Picture 2, shows the extension board I built. The extension board increases the number of available LED’s and switches. The board is attached via a ribbon cable with the ends of the wire inserted into the green and orange screw down chocolate blocks attached to the Piface Digital IO board.

Command to toggle between play and pause in moc is
mocp -G or mocp –toggle-pause
moc man page https://www.mankier.com/1/mocp
moc homepage http://moc.daper.net/

Uptime man page https://linux.die.net/man/1/uptime

Explanation of how to read a binary display

The board I built which attaches to the Piface Digital board has a total of 8 LED’s. I use the 8 LED’s to display a number in binary format. In binary each LED has only two values either on or off, with 1 LED you can count to 1 with two LED’s you can count to 3. This may seem confusing if you’ve never dealt with binary before. Starting from the right each subsequent LED represents double the value of the previous one so the 1st LED has a value of 1 the 2nd LED has a value of 2, the third LED has a value of 4 and so on. See below

LED Number 8 7 6 5 4 3 2 1 LED VALUES 128, 64, 32, 16, 8, 4, 2, 1

LED on represents 1, LED off represents 0

[Example 1] 0 0 0 0 0 0 0 1 [Represented value 1]
1st LED on value = 1

[Example 2] 0 0 0 0 0 0 1 1 [Represented value 3]
1st and 2nd LED on, LED VALUE 1 + 2 = 3

[Examples 3] 0 0 0 0 1 0 1 0 [Represented value 10]
2nd and 4th LED on, LED VALUE 2 + 8 = 10

With practice it gets easy to convert from binary to decimal, at my work we still have a very old computer which contains a front panel with LED’s and binary switches. To load the computer instructions must be loaded in binary using flip switches and LED’s with practice it becomes second nature.


Further information on binary numbers https://en.wikipedia.org/wiki/Binary_number

df man page (Disk Free) https://linux.die.net/man/1/df

aplay man page https://linux.die.net/man/1/aplay

HPR2899: Endeavour OS

Sep 12, 2019


Hi to all you out there in HPR land, this is a quick show to help out with the current summer shortage of shows.

So over the last few months I’ve been busy with my new Podcasting career, well it fills in the time now I’m retired. Anyway the Distro-hoppers show has been getting a regular audience and recently we decided to branch out a little and open up the review format to the audience, you can find details of how to do that on the Blog.

The most recent show was a review of the new Endeavour OS which has risen from the ashes of Antergos Linux an Arch based OS. Well I decided to use this opportunity to delve into the world of Arch for the first time with Endeavour OS and I can report I was pleasantly surprised with this slick iteration of Arch. OK when you first install Endeavour all you will have is a new XFCE 4.14 DE and some basic software to get you started, you are then expected to do a little research to find out how to install other software you need to get your PC setup the way you like but all the basic information on package management is on the Endeavour OS Wiki and also on the Arch Linux Wiki.

If you have thought of trying Arch Linux but would prefer to start with a running Desktop from install then Endeavour OS is definitely the place to start. I have been running it as my daily Driver for over a month and have fallen in love with it.
My full review is on the Distrohoppers Blog as is a link to the Audio of the show.

That’s it for this time, this is Tony Hughes saying goodbye until next time.




HPR2898: Modeling people in space game

Sep 11, 2019


People are what makes dynasty simulators interesting and this episode will be about them. There isn’t much code this time, mainly just how data is organized. Topic is long and split over several episodes.

Some people in game are controlled by computer, while some are controlled by player. There’s no difference on what each can do in game, computer is basically just filling in for players when there aren’t enough players.

There’s plenty of data about people, spread over several entities and database tables. Main one is Person, which stores name, gender, sex, date of birth and some stats (and then some more).

There are lots of various ways of naming people and I chose to model three for the starters:

data PersonName = RegularName FirstName FamilyName (Maybe Cognomen) | SimpleName FirstName (Maybe Cognomen) | RegalName FirstName FamilyName RegnalNumber (Maybe Cognomen) deriving (Show, Read, Eq)

The higher the rank, more complicated names you tend to have (for some reason). Later on I’ll try and see if I can add more varied names, like matronyms and patronyms.

Sex and gender I’m modeling with simple system of two enumerations, sex can be Female, Male or Intersex, while gender has values Man, Woman, Agender and Nonbinary. System is coarse, but should be enough to get started with the game. Later on, this can be expanded to more nuanced system.

Traits are defining features of people. These include things like brave, coward, ambitious, content, honest and such. Values are binary, character either is brave or not. And character can’t be brave and coward at the same time.

Relations are modeled as PersonRelation and thus stored in person_relation table:

Relation json originatorId PersonId targetId PersonId type RelationType visibility RelationVisibility deriving Show Read Eq

I find this corner of the puzzle particular interesting. This models who is parent or child, who is friend or rival. Interconnected web created by relations isn’t completely visible to players (or any other person in game). Relations have visibility, modeled as RelationVisibility, which tells how visible it is. Public ones are known by everyone, family relations are limited to small group of people and secret relations are only known by those who are in the fold. One aspect of the game is acquiring this information.

Intel is modeled as HumanIntelligence and stored in human_intelligence table:

HumanIntelligence json personId PersonId ownerId PersonId level PersonIntel deriving Show Read Eq

Essentially it just lists which character has what information about certain other character. So when displaying information to players, this table has to be referenced in order to know how much to reveal to them.

Different types of intels are listed as PersonIntel:

data PersonIntel = Stats | Demesne | FamilyRelations | SecretRelations | Opinions OpinionIntel | Traits deriving (Show, Read, Eq)

Person related data is sent back to client in PersonReport record (I’m not copying it here as it’s relatively large). We can have a look on how one field is processed.

For example, in case of traits. PersonReport has field personReportTraits :: !(Maybe [TraitReport]). Exclamation mark in the beginning of type instructs Haskell that this value should be computed immediately when record is created and not left for later. I’m doing this as I know for sure that it’ll always be used and there’s no advantage on delaying computation for the time when it might be needed.

Report creating (high level):

personReportTraits = if Traits `elem` targetIntel then Just $ traitReport <$> targetTraits else Nothing

That first checks that Traits level of intel is available and then creates list of trait reports (one for each trait person has). These have things like trait name, description, trait type and how long the trait is valid. Having separate name and description fields makes it easier to work on client side as I don’t have to come up with descriptions there anymore. I can just use what the server sends to me and be happy.

Comments, questions and feedback are welcome. Best way to catch me nowadays is email or fediverse where I’m tuturto@mastodon.social.

HPR2897: Stardrifter RPG Playtest Part 03

Sep 10, 2019


This episode is Part 3 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this part, we continue to go over the rules of the game, and then start into the adventure!

Special thanks to my playtesters: Klaatu, Thaj, Mark (who was playing Brinn), and Brian!

HPR2896: Orange PI Zero LTS version

Sep 9, 2019


A general overview of the Orange PI Zero LTS version

This is the one I really liked

This is were the software is

HPR2895: The work of fire fighters, part 2

Sep 6, 2019


Continued general basic knowledge of fire fighting.
Also an extended invitation to ask questions in the comments.
ps: I started making podcasts one year ago! o/

HPR2894: Repairing a Musical Instrument Case

Sep 5, 2019


In this episode I talk about repairing the case for a Vietnamese Đàn tranh, a zither-like instrument which was donated to the School of Music by a member of the community. I also demonstrate the instrument as best I can so that you can hear what it sounds like.

See the Flickr photo album that accompanies this show by clicking the image below.

Dan Tranh Case Repair

Links Đàn tranh Contact cement Pentatonic scale Credits Music bumpers are from Kimiko Ishizaka's The Open Goldberg Variations: http://www.opengoldbergvariations.org/, used by permission of their CC0 1.0 Universal (CC0 1.0) Public Domain Dedication license.

HPR2893: Whats in the box! Part 2

Sep 4, 2019


In this short follow up episode NYbill troubleshoots the Tremlo guitar kit Timttmy sent him.

Here is a hint, there were two problems, not just one.

Pics for the episode:


HPR2892: Stardrifter RPG Playtest Part 02

Sep 3, 2019


This episode is Part 2 of the Stardrifter role-playing game playtest. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this part, we continue to go over the rules of the game, and discuss them in some detail.

Special thanks to my playtesters: Klaatu, Thaj, Mark (who was playing Brinn), and Brian!

HPR2891: HPR Community News for August 2019

Sep 2, 2019


table td.shrink { white-space:nowrap } New hosts

There were no new hosts this month.

Last Month's Shows Id Day Date Title Host 2869 Thu 2019-08-01 building a bike, following in John Kulp's footsteps Brian in Ohio 2870 Fri 2019-08-02 Hierarchy of Evidence Ahuka 2871 Mon 2019-08-05 HPR Community News for July 2019 HPR Volunteers 2872 Tue 2019-08-06 Shoe Lace Tips MrX 2873 Wed 2019-08-07 Death Angel - Card game tuturto 2874 Thu 2019-08-08 Repair of G.E. Variable Speed Cassette Recorder Jon Kulp 2875 Fri 2019-08-09 cutting up the frames Brian in Ohio 2876 Mon 2019-08-12 Sausage Orzotto Windigo 2877 Tue 2019-08-13 Using Zenity with Pdmenu Dave Morriss 2878 Wed 2019-08-14 Type classes in Haskell tuturto 2879 Thu 2019-08-15 Describing how I listen to podcasts PART 1 MrX 2880 Fri 2019-08-16 Evaluating a Study Ahuka 2881 Mon 2019-08-19 Automatically split album into tracks in Audacity Ken Fallon 2882 Tue 2019-08-20 ONICS Part 1: Basic Commands Gabriel Evenfire 2883 Wed 2019-08-21 Pass the pigs tuturto 2884 Thu 2019-08-22 TASCAM Porta 02 MiniStudio 4-Track Cassette Recorder Demonstration Jon Kulp 2885 Fri 2019-08-23 ONICS Part 2: Filtering and Extraction Gabriel Evenfire 2886 Mon 2019-08-26 INFOSECOND operat0r 2887 Tue 2019-08-27 Stardrifter RPG Playtest Part 01 lostnbronx 2888 Wed 2019-08-28 Pattern matching in Haskell tuturto 2889 Thu 2019-08-29 Describing how I listen to podcasts PART 2 MrX 2890 Fri 2019-08-30 Penguicon 2019 Report Ahuka Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 24 comments in total.

Past shows

There are 7 comments on 2 previous shows:

hpr2859 (2019-07-18) "HPR NYE Show 2018-2019 part 7" by Honkeymagoo. Comment 3: Mike Ray on 2019-08-05: "First hour" Comment 4: MrsXoke on 2019-08-05: "To Mike Ray" Comment 5: Mike Ray on 2019-08-06: "To Mike Ray" Comment 6: Mike Ray on 2019-08-06: "Active shooter drills" Comment 7: Mike Ray on 2019-08-06: "Faith and values" Comment 8: folky on 2019-08-08: "You can fastforward"
hpr2863 (2019-07-24) "Simplified application architectures for improved security" by Beeza. Comment 1: clacke on 2019-08-14: "Dynamic vs static linking doesn't matter"
This month's shows

There are 17 comments on 7 of this month's shows:

hpr2869 (2019-08-01) "building a bike, following in John Kulp's footsteps" by Brian in Ohio. Comment 1: Jon Kulp on 2019-08-01: "Recycled Recumbents"
hpr2876 (2019-08-12) "Sausage Orzotto" by Windigo. Comment 1: Bookewyrmm on 2019-08-12: "Salt"Comment 2: Windigo on 2019-08-17: "Re: Salt"Comment 3: Dave Morriss on 2019-08-20: "Loved this. I was right there with you in the kitchen"
hpr2881 (2019-08-19) "Automatically split album into tracks in Audacity" by Ken Fallon. Comment 1: Jonathan Kulp on 2019-08-22: "Automation is nice"
hpr2882 (2019-08-20) "ONICS Part 1: Basic Commands" by Gabriel Evenfire. Comment 1: Dave Morriss on 2019-08-22: "Great project and excellent show"Comment 2: Gabriel Evenfire on 2019-08-25: "Good to hear"
hpr2884 (2019-08-22) "TASCAM Porta 02 MiniStudio 4-Track Cassette Recorder Demonstration" by Jon Kulp. Comment 1: Clinton Roy on 2019-08-22: "fantastic"Comment 2: tuturto on 2019-08-22: "awesome"Comment 3: jezra on 2019-08-22: "super fun!"Comment 4: Jon Kulp on 2019-08-22: "By ear"Comment 5: mcnalu on 2019-08-24: "4tracks4TW"Comment 6: Jon Kulp on 2019-08-24: "Can’t bounce"Comment 7: johanv on 2019-08-29: "great show"
hpr2887 (2019-08-27) "Stardrifter RPG Playtest Part 01" by lostnbronx. Comment 1: tuturto on 2019-08-27: "Eagerly waiting for more"Comment 2: Ken Fallon on 2019-08-28: "A future podcast in the future feed"
hpr2890 (2019-08-30) "Penguicon 2019 Report" by Ahuka. Comment 1: Dave Morriss on 2019-08-31: "solder/"sodder"/souder"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-August/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Tags and Summaries

Thanks to the following contributor for sending in updates in the past month: Dave Morriss

Over the period tags and/or summaries have been added to 10 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2890: Penguicon 2019 Report

Aug 30, 2019


Penguicon 2019 is a combined technology and science fiction convention in Southfield, Michigan, a suburb of Detroit, and presents over 500 hours of programming over the entire weekend. Of this, around 100 hours are open source, tech-related. In this episode I tell you about my own personal experience at Penguicon this year.

Links https://2019.penguicon.org/ https://en.wikipedia.org/wiki/Saladin_Ahmed http://www.mikeymason.com/ https://zedshaw.com/ https://www.facebook.com/CraftyCelts/posts/d41d8cd9/233607537127/ https://www.sophiabrueckner.com/ https://www.facebook.com/public/Karen-Corbeill https://www.youtube.com/playlist?list=PLwO8CTSLTkii9S_vhEOsyJ17RI3jjBZ95 http://www.allhandsactive.org/ https://www.zwilnik.com

HPR2889: Describing how I listen to podcasts PART 2

Aug 29, 2019


Short Summary

In this series I cover how I listen to podcasts and how the process has change over the years. In this episode I cover the hardware I’ve used over the years to listen to podcasts.

Link to HPR 2112 (Home Server) episode mentioned in this podcast

Link to HPR 2106 (Hpodder) Episode mentioned in this podcast

The cordless headphones I use are analogue cordless headphones they operate in the UHF 860 MHz RF spectrum and use Frequency modulation

(Picture 01) shows a pair of JVC cordless headphones, these were my first pair of cordless headphones, from memory they were reasonably comfortable and lasted a reasonably long time, they eventually gave way when the strap along the top completely split if you look carefully you can see evidence of this in the picture. Picture-01.JPG

I think my 2nd set pair of cordless headphones were made by Phillips, unfortunately I don’t have a picture of these. The headphones were too big and kept falling from my head.

(Picture 02) shows a pair of Sony headphones that I can’t even remember owning! I’ve lost count of how many cordless headphones I’ve owned over the years, these were also too big and regularly fell off my head, there are probably other pairs which I have forgotten about. It took a lot of trial an error to find a pair that would fit properly. Picture-02.JPG

I think my 3rd set of cordless headphones were a cheap pair from Liddles, unfortunately I don’t have a picture of these again these were also too big.

(Picture 03) Shows my current set of cordless headphones, unfortunately my camera refused to work while taking this picture so you’ll not be able to identify the manufacturer which is a great pity as they are absolutely great also the lighting in here is very bad so you won’t be able to make out the writing printed on them :) Picture-03.JPG

Compaq N610C laptop


EEE PC Laptop

Pictures (04 and 05) are of my Nokia N810 Picture-04.JPG

Below is a link from wikipedia covering the Nokia N810.

Links to shows where klaatu references the Nokia N770 which came out before the Nokia N810 but is very similar

Nexus 7, first generation

Psion 3C

Raspberry pi

HPR2888: Pattern matching in Haskell

Aug 28, 2019


Pattern matching is one of those features of Haskell that immediately got me interested as it reduces amount of branching inside of functions I write. Basic idea is that if value constructors are for making data, pattern matching is for taking it apart.

First example is a function that takes a Bool and returns a respective String:

boolToString :: Bool -> String boolToString n = if n then "True" else "False"

Nothing too fancy, just an if expression inside a function. We can move that if out of there though and define exactly same functionality, but with patterns:

boolToString :: Bool -> String boolToString True = "True" boolToString False = "False"

There’s one definition for boolToString, but two different patterns used.

Second example is bit more complex, this time we have Maybe Int that is being turned into String. Maybe has two value constructors Nothing and Just a. We have two cases for Just, specific one for when it’s Just 1 and more general one Just n that takes care of rest of the cases.

isBig :: Maybe Int -> String isBig Nothing = "Not at all" isBig (Just 1) = "Just perfect" isBig (Just n) = if n < 10 then "Just slightly" else "Definitely is"

Some example usage:

> isBig Nothing "Not at all" > isBig $ Just 0 "Just perfect" > isBig $ Just 50 "Definitely is"

Pattern matching isn’t limited to algebraic datatypes that we have been working with so far. We can do same things with records. Below is an function used to calculate total fee when cost and customer are known. Each customer can have their own discount percentage, but in addition we’re giving 10% discount to VIP customers:

data Customer = Customer { customerName :: String , customerDiscountPct :: Double , vipCustomer :: Bool } totalFee :: Double -> Customer -> Double totalFee bill cust@(Customer { vipCustomer = True }) = bill * 0.9 * customerDiscountPct cust totalFee bill cust = bill * customerDiscountPct cust

There’s two cases of totalFee function. First one is for when passed in Customer has vipCustomer field True. Second one takes care of general case. In the first case we’re using @ to bind Customer as a whole to cust name.

Lists can be matched too. The basic idea is exactly the same:

(x:xs) matches a list with at least one item, x is first item, xs is rest of the items (might be an empty list) (x:y:_) matches two first items in a list of at least two items, x is first, y is second, _ is rest [] matches empty list (x:[]) matches list of exactly one item

Underscore _ matches to everything without binding value to a name. This is useful when you don’t care about exact value, so you don’t want to give it a name. One could give it a name, but compiler will issue a warning if there are unused values in the code.

Next example is recursively counting amount if items in a list using pattern matching:

count :: [a] -> Int count [] = 0 count (x:xs) = 1 + count xs

Fibonacci series is series of number which starts with 0, 1 and then rest of the numbers are sum of two previous ones: 0, 1, 1, 2, 3, 5, 8…

To calculate number in series, we can write following code (this is extremely slow way of calculating them by the way):

fibonacci :: Int -> Int fibonacci 0 = 0 fibonacci 1 = 1 fibonacci n = fibonacci (n - 1) + fibonacci (n - 2)

Last trick in our sleeve for now is case expression. This allows us to do pattern matching inside of a function. Otherwise it works in the same way. Our fibonacci function could be defined as:

fibonacci :: Int -> Int fibonacci n = case n of 0 -> 0 1 -> 1 n -> fibonacci (n - 1) + fibonacci (n - 2)

Questions, comments and feedback are welcome. Best way to catch me nowadays is either email or in fediverse where I’m tuturto@mastodon.social

HPR2887: Stardrifter RPG Playtest Part 01

Aug 27, 2019


This episode begins a limited series covering the first playtest of a new role-playing game, based upon my Stardrifter series of books and short stories. The series is composed of two playtest sessions, held earlier this year. They were recorded and chopped into manageable bites, then edited down into separate episodes.

This series is meant to give listeners some insight into the RPG construction process. Playtesting is not the final step, but rather, just another stage. The construction of an RPG can be convoluted, and feedback from players is absolutely vital.

In this first episode, as well as the next, we we go over the rules of the game, and discuss them in some detail.

Special thanks to my playtesters: Klaatu, Thaj, Mark (who was playing Brinn), and Brian!


Aug 26, 2019


In todays show, operat0r shares his personal thoughts around information security and getting into the field. He also talks about ways to get support from your local community.

HPR2885: ONICS Part 2: Filtering and Extraction

Aug 23, 2019


In this episode we'll talk about filtering and dissecting packet traces and streams and introduce diffing. Remember that most tools have very flexible options for a variety of use cases. So check their manpages. Each man page also has multiple examples of how to use each tool.

Counting Packets Lets start with grabbing a trace from the unit tests: $ mkdir /tmp/packets $ cd /tmp/packets $ cp /path/to/onics/tests/data/packets/sample.xpkt . Lets see what we have inside. First, lets see how many packets there are. We'll use a new tool 'pcount'. $ pcount sample.xpkt 90 total packets and 19082 total bytes. Good thing we looked first. Don't want to walk through all the packets. Scanning Packet Flows

Well, lets look at the connections or "flows" in the trace. We'll do this by using the 'nftrk' command for "network flow tracker".

Like 'pcount' this utility (and many or most ONICS utilities), this program can run on a live stream or a trace file. We'll run:

$ nftrk -dt sample.xpkt | grep END

and get:

|FLOW END|IP:ca=,sa=,proto=2|Start=1565446184.543, End=1565446184.544,Dur=0.001|SENT:1,60| ... |FLOW END|IP:ca=,sa=,proto=17,cpt=631,spt=631| Start=1565446184.543,End=1565446184.544,Dur=0.001|SENT:3,660|

'nftrk' tracks flows giving events like the start and end of each flow or connection. We just want a summary of all the connections so we just grep for 'END' (all caps).

We could just as easily have grepped for START, but this way we get the final number of packets sent and received on each connection. If we just want a count of the connections we can do:

$ nftrk -dt sample.xpkt | grep START | wc -l

and that tells us that there are 10 flows in the trace.

Basic Filtering Ok, so 90 packets, in 10 flows totalling ~19000 bytes. Lets now see about filtering the connection so we just get the TCP packets. $ pflt tcp sample.xpkt tcponly.xpkt $ pcount tcponly.xpkt 73 total packets and 17184 total bytes. $ nftrk -dt tcponly.xpkt | grep END | wc -l 2 We could have been super fancy and done: $ pflt tcp sample.xpkt | pcount -p | nftrk -t 2>/tmp/flows > tcponly.xpkt && echo -n "Number of flows " && grep END /tmp/flows | wc -l && rm -f /tmp/flows Ok, enough of that. Anyway, now we have a trace file with only the TCP connections. Running $ nftrk -dt /tmp/tcponly.xpkt | grep END |FLOW END|IP:ca=,sa=,proto=6,cpt=38859,spt=22| Start=1566073862.612,End=1566073862.613,Dur=0.000|C2S:25,4561|S2C:30,5124| |FLOW END|IP:ca=,sa=,proto=6,cpt=35071,spt=80| Start=1566073862.613,End=1566073862.613,Dur=0.000|C2S:9,704|S2C:9,6795|

Shows that the server ports are 22 and 80 for the two connections. That's SSH and HTTP.

The patterns we can use to filter packets are pretty standard across most of the ONICS tools.

We'll discuss this is more detail in a future podcast. But if you want to see the kinds of fields you can match on go to

$ man onics_proto Extracting Ranges of Packets What if we wanted to just grab specific packets out of the trace file? Say we wanted packets 3-6. For that we would run: $ pxtr 3,6 sample.xpkt pkts-3-to-6.xpkt Alternately we could ask for all packets from the 7th packet to the first TCP packet. We match using the same types of matching conditions as with pflt, but we must enclose them in {}s. $ pxtr "7,{tcp}" sample.xpkt | xpktdump Lets say we just wanted to drop packets 5-10 from the stream. There are several ways to do this in ONICS, but using pxtr, the way we would do it would be: $ pxtr 1,4 sample.xpkt > not-5-to-10.xpkt $ pxtr 11,NONE sample.xpkt >> not-5-to-10.xpkt Maybe I should add another option to pxtr to invert the boundary conditions. It's a tradeoff between having the tools do one thing and one thing well and supporting a potentially common use case. Differences Between Traces Finally, lets look at one tool that I really like. Let's see the difference between the original stream and the one that we just created: $ pdiff sample.xpkt not-5-to-10.xpkt | less Sure enough that shows us that packets 5-10 were dropped from the stream. If we do the reverse $ pdiff -v not-5-to-10.xpkt sample.xpkt | less

it describes the sample.xpkt from the perspective of starting with not-5-to-10.xpkt and inserting a bunch of packets into the middle.

Conclusion In this podcast we looked at a few tools to help analyze and dissect packet traces or packet streams. Next time we'll look at some of the more powerful pattern matching we can apply and

HPR2884: TASCAM Porta 02 MiniStudio 4-Track Cassette Recorder Demonstration

Aug 22, 2019


I discuss and demonstrate the latest retro gadget I found at the flea market last weekend, a TASCAM Porta 02 MiniStudio 4-Track Cassette Recorder. It was in a bin full of junk—filthy, lacking its power supply, and I got it for only $5. I hacked a power supply, disassembled it completely, washed everything thoroughly, and put it back together. It worked perfectly with the exception of the pause button. This has been one of the most fun projects I can remember, especially because my daughter is into it too, and she's learning how to make multi-track recordings. I always wanted a 4-track when I was in high school but never had one. Now I do!

TSACAM Porta 02 4-Track Recording Demonstration

Links to info about stuff I mentioned Flickr album with photos from this recording session Flickr album with photos from the TASCAM machine restoration My earlier episode about the Marantz recorder: hpr1844 :: The Marantz PMD 660 Professional Solid State Recorder My video of the TASCAM testing, power supply hack, disassembly, and cleaning: Watch on YouTube Multitrack recording Güiro (mine is metal) Clave (instrument) and clave rhythm (you heard the 2-3 clave rhythm on this podcast) Diatonic harmonica Chromatic harmonica Microphone types Phantom power Clipping EQ: Equalization Mixing Mastering Demo Recordings The TASCAM PortaStudio David Mead (his first two albums were with RCA, not Polygram My first test recording on the restored TASCAM Porta 02: Listen on Soundcloud

HPR2883: Pass the pigs

Aug 21, 2019


For more information, have a look at https://boardgamegeek.com/boardgame/2593/pass-pigs

HPR2882: ONICS Part 1: Basic Commands

Aug 20, 2019



It's been about 6 years since I talked about my project ONICS in HPR 1350 ONICS stands for Open Network Inpection Command Suite I created ONICS as because I thought it would be neat to have a suite of tools that could manipulate packets on the command line in a way similar to how tools lik sed, awk, grep, cut, and so forth manipulate text.


Not currently maintained in any package distributions Maintainers who are interested in doing so are welcome Install by source $ git clone https://gitlab.com/catlib/catlib $ cd catlib $ make $ cd .. $ git clone https://gitlab.com/onics/onics $ cd onics $ ./configure $ make $ make test $ sudo make install $ make veryclean Can always uninstall cleanly from the source directory $ make uninstall Alternate to installation is to stop at 'make test' and then add to 'onics/bin' and 'onics/scripts' to your path.


Manpages are available in onics/doc directory if you aren't installing locally. They are quite extensive.

If installed locally, starting with:

$ man onics

XPKT Format

PCAP format is outdated and not very extensible

I want to be able to annotate with interface IDs, flow IDs, packet numbers, classification info, header offsets, etc...

First and foremost, the file header prevents just cating files together.

it makes merging live streams more difficult pcapng improves things but still has global file header

First Programs

Let's first capture in the traditional way $ sudo tcpdump -i eth0 -c 5 -w file1.pcap First program is to capture packets from the wire: $ sudo pktin eth0 > file2.xpkt If not running as root $ sudo chown myname file1.pcap file2.xpkt Let's dump them: $ tcpdump -r file1.pcap $ xpktdump file2.xpkt Now lets convert the PCAP to XPKT $ pc2xpkt file1.pcap file1.xpkt or $ pc2xpkt file1.pcap > file1.xpkt or $ pc2xpkt < file1.pcap > file1.xpkt or $ cat file1.pcap | pc2xpkt > file1.xpkt Now we can dump file1 using xpktdump: $ xpktdump file1.xpkt

Something we can't do w/ tcpdump

Lets now merge them one after another $ cat file1.xpkt file2.xpkt > merged.xpkt $ xpktdump merged.xpkt Of course there's a simpler way $ cat file1.xpkt file2.xpkt | xpktdump

Convert back to pcap:

Let's convert file2 to PCAP $ xpkt2pc file2.xpkt file2.pcap or $ xpkt2pc < file2.xpkt > file2.pcap or $ xpkt2pc file2.xpkt > file2.pcap or $ cat file2.xpkt | xpkt2pc > file2.pcap Let's look at the stream using tcpdump: $ tcpdump -r file2.pcap If we didn't want to actually store as a PCAP $ xpkt2pc file2.xpkt | tcpdump -r - Let's concatenate and dump using tcpdump $ cat file1.xpkt file2.xpkt | xpkt2pc | tcpdump -r | less

Sending packets:

$ sudo tcpdump -i eth0 # in one terminal $ sudo pktout -i eth0 file1.xpkt or $ sudo pktout -i eth0 < file1.xpkt or $ cat file1.xpkt | sudo pktout -i eth0


XPKT is a versatile, extensible, self-contained packet trace format ONICS' most basic tools are pktin, pktout, pc2xpkt and xpkt2pc We've demonstrated how the ONICS design supports leveraging the power of the UNIX command line for packets This is only the VERY beginning. ONICS has over 20 binaries and 30 scripts for manipulating packets.

HPR2881: Automatically split album into tracks in Audacity

Aug 19, 2019


In this show Ken, recalls hpr1771 :: Audacity: Label Tracks by Jon Kulp to add Labels to an large audio file.

Tidy up the audio to the point where you are happy with it, but do not truncate silence. Find the first break in the audio and check how long it is. In my case it was 4 seconds. Select the entire track and select Analyze>Silence Finder Change Maximum duration of silence to just under the length of the break. In my case I set it to 3 seconds This will then create a series of labels on a new Label track Edit the names of each as desired. Select File > Export > Export Multiple Select Split Files based on Labels Name files using Label/Track Name

HPR2880: Evaluating a Study

Aug 16, 2019


We take the ideas we have developed over the previous episodes and use them to evaluate a a study I found online. These are things anyone can do with just a little work on Google, and the payoff is to have a good idea of whether or not you are looking at a quality study

Links https://www.medicalnewstoday.com/ https://www.medicalnewstoday.com/articles/324558.php https://mediabiasfactcheck.com/medical-news-today/ https://www.quora.com/How-can-I-find-a-replication-of-a-study https://en.m.wikipedia.org/wiki/Web_of_Science https://www.nature.com/articles/s41551-019-0356-9#MOESM1 https://www.nature.com/natbiomedeng/ https://www.nature.com/articles/s41551-019-0356-9 https://www.palain.com/?page_id=404

HPR2879: Describing how I listen to podcasts PART 1

Aug 15, 2019


In this series I cover how I listen to podcasts and how the process has change over the years. This episode badly covers the console audio player moc.

Link to HPR 2112 (Home Server) episode mentioned in this podcast

My first MP3 player was a Jelly Bean shaped MP3 player apparently known as an S1 MP3 player

Sansa Clip info on wikipedia

Raspberry Pi

Music On Console (MOC) is an ncurses-based console audio player for Linux/UNIX

Here is a link to information about moc on wikipedia

On a Debian based system Moc can be installed by issuing the following command
sudo apt-get install moc Link to Moc, Music On Console homepage

HPR2878: Type classes in Haskell

Aug 14, 2019



Type classes are Haskell’s way of doing ad hoc polymorphics or overloading. They are used to defined set of functions that can operate more than one specific type of data.


In Haskell there’s no default equality, it has to be defined.

There’s two parts to the puzzle. First is type class Eq that comes with the standard library and defines function signatures for equality and non-equality comparisons. There’s type parameter a in the definition, which is filled by user when they define instance of Eq for their data. In that instance definition, a is filled with concrete type.

class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x /= y = not (x == y)

Definition above can be read as “class Eq a that has two functions with following signatures and implementations”. In other words, given two a, this function determines are they equal or not (thus Bool as return type). /= is defined in terms of ==, so it’s enough to define one and you get other one for free. But you can still define both if you’re so included (maybe some optimization case).

If we define our own Size type, like below, we can compare sizes:

data Size = Small | Medium | Large deriving (Show, Read) instance Eq Size where Small == Small = True Medium == Medium = True Large == Large = True _ == _ = False

And here’s couple example comparisons.

> Small == Small True > Large /= Large False

Writing these by hand is both tedious and error prone, so we usually use automatic derivation for them. Note how the second line now reads deriving (Show, Read, Eq).

data Size = Small | Medium | Large deriving (Show, Read, Eq) Hierarchy between type classes

There can be hierarchy between type classes, meaning one requires presence of another. Common example is Ord, which is used to order data.

class Eq a => Ord a where compare :: a -> a -> Ordering (<) :: a -> a -> Bool (>=) :: a -> a -> Bool (>) :: a -> a -> Bool (<=) :: a -> a -> Bool max :: a -> a -> a min :: a -> a -> a

This definition can be read as “class Ord a, where a has instance of Eq, with pile of functions as follows”. Ord has default implementation for quite many of these, in terms of others, so it’s enough to implement either compare or <=.

For our Size, instance of Ord could be defined as:

instance Ord Size where Small <= _ = True Medium <= Small = False Medium <= _ = True Large <= Large = True Large <= _ = False Writing generic code

There’s lots and lots of type classes in standard library:

Num for numeric operations Integral for integer numbers Floating for floating numbers Show for turning data into strings Read for turning strings to data Enum for sequentially ordered types (these can be enumerated) Bounded for things with upper and lower bound and so on…

Type classes allow you to write really generic code. Following is contrived example using Ord and Show:

check :: (Ord a, Show a) => a -> a -> String check a b = case compare a b of LT -> show a ++ " is smaller than " ++ show b GT -> show a ++ " is greater than " ++ show b EQ -> show a ++ " and " ++ show b ++ " are equal"

Check takes two parameters that are same type and that type has to have Ord and Show instances. Ord is for ordering and Show is for turning data into string (handy for displaying it). The end result is string telling result of comparison. Below is some examples of usage. Note how our function can handle different types of data: Size, Int and [Int].

> check Medium Small "Medium is greater than Small" > check Small Large "Small is smaller than Large" > check 7 3 "7 is greater than 3" > check [1, 2] [1, 1, 1] "[1, 2] is greater than [1, 1, 1]"

There are many extensions to type classes that add more behaviour. These aren’t part of standard Haskell, but can be enabled with a pragma definition or compiler flag. They can be somewhat more complicated to use, have special cases that need careful consideration, but offer interesting options.

In closing

Thank you for listening. Question, comments and feedback welcome. Best way to catch me nowadays is either by email or in fediverse, where I’m tuturto@mastodon.social.

HPR2877: Using Zenity with Pdmenu

Aug 13, 2019



I use pdmenu a lot to help me do work on my main desktop PC. I did an HPR show on pdmenu on 13 December 2017 and the author Joey Hess responded in show 2459.

In the intervening time I have also integrated Zenity into my menus. This is a GUI tool which generates a number of different pop-up windows known as dialogs, which can display information, or into which information can be typed. The capabilities provided by pdmenu are a little too basic to enable me to do what I need to do.

I thought it might be of interest to show some examples of how I use this tool with pdmenu.

Long notes

I have provided detailed notes as usual for this episode, and these can be viewed here.

Links Pdmenu: Pdmenu website Joey Hess Zenity Wikipedia page Zenity Manual

HPR2876: Sausage Orzotto

Aug 12, 2019


This recipe has been heavily adapted from one I received from Hello Fresh - credit where credit's due!


1 lb (500g) Sausage (chicken or pork works) 1 ½ cups (192g) Orzo 2 tbsp (40g) Butter Olive oil Zucchini Shallot 1 - 2 tbsp (20-40g) Italian Seasoning Pepper 2 cups (475ml) water 1 tsp (4g) stock concentrate 16oz (450g?? One normal can, whatever that is) Crushed or diced tomatoes 1 cup (226g) Mozzarella cheese (shredded) Panko Breadcrumbs Salt (Optional) Mince half the shallot (or all of it, I'm not the boss of you). Trim and shred the zucchini. Prepare a mixing bowl lined with a paper towel. Preheat oven to 500 F Drizzle some oil into a large oven-proof pan (if you've got one) and cook the sausage, with half the Italian seasoning, over medium heat, breaking it into bite-sized pieces as you cook it. Transfer to the mixing bowl for later. Add another drizzle of olive oil, and shred the zucchini into the pan. Add shallot, and cook until the zucchini shrinks to ⅔ of its size (about 5 minutes). Transfer to the mixing bowl with the sausage. Wipe out the pan with a paper towel. Melt 1 tbsp of butter over medium heat, and add orzo, stirring pretty frequently for 2-3 minutes. Stir in the rest of the Italian seasoning, along with the water, tomatoes, and stock concentrate. Bring to a boil and stir until orzo is done - around 12 - 14 minutes. Drain excess liquid from the zucchini and sausage. Mix sausage & zucchini into orzo mixture, with 1 tbsp of butter. Season with salt & pepper, if you want. If you don't have an oven-proof pan, you're going to want to transfer everything over to a large baking dish of some kind. 13x9" works for me. Cover the mixture in mozzarella cheese and panko breadcrumbs - in that order! Place dish in the oven for 2-3 minutes, until the breadcrumbs are toasted.

Note: If these metric measurements seem crazy, they probably are.

HPR2875: cutting up the frames

Aug 9, 2019





One of the donors


The gold

First cut

Cutting tubes


Frame 2 parts

Frame 1 parts

HPR2874: Repair of G.E. Variable Speed Cassette Recorder

Aug 8, 2019


I found a pretty cool little handheld cassette recorder at Salvation Army Thrift Store for 99 cents yesterday. It was non-functioning. I was able to get it working again by 1. cleaning corrosion from battery compartment; 2. replacing the nasty gooey belt; 3. repairing the battery compartment, which had a broken-off spring for one of the battery's negative connections. The most interesting feature of the device is that it has a variable-speed knob for playback at higher speed. I demonstrate this in the podcast.

G.E. Variable Speed Cassette Recorder Repair

Links to Stuff Mentioned in the Episode Flickr Photo Album Assorted cassette deck belts on eBay Kahoot! Make Learning Awesome.

HPR2873: Death Angel - Card game

Aug 7, 2019


For more information, have a look at BoardGameGeek: https://boardgamegeek.com/boardgame/71721/space-hulk-death-angel-card-game

HPR2872: Shoe Lace Tips

Aug 6, 2019


In this episode I give some shoe lace tips

Shoe Laces Ted Talk with over 6.5 million views

Some further info on the shoe lace knot from the wonderful wikipedia site

Fast tie shoe laces recommended for anyone in a hurry

HPR2871: HPR Community News for July 2019

Aug 5, 2019


table td.shrink { white-space:nowrap } New hosts

Welcome to our new host:

Last Month's Shows Id Day Date Title Host 2846 Mon 2019-07-01 HPR Community News for June 2019 HPR Volunteers 2847 Tue 2019-07-02 earbuds operat0r 2848 Wed 2019-07-03 Random numbers in Haskell tuturto 2849 Thu 2019-07-04 HPR NYE Show 2018-2019 part 5 Honkeymagoo 2850 Fri 2019-07-05 NIST Cybersecurity Framework Ahuka 2851 Mon 2019-07-08 An introduction to the work of fire fighters Jeroen Baten 2852 Tue 2019-07-09 Gnu Awk - Part 16 Dave Morriss 2853 Wed 2019-07-10 Feeding the beast folky 2854 Thu 2019-07-11 Telling myself something In The Morning Jezra 2855 Fri 2019-07-12 HPR NYE Show 2018-2019 part 6 Honkeymagoo 2856 Mon 2019-07-15 Mint Mobile Security Rant operat0r 2857 Tue 2019-07-16 Creating CounterParty Collectible Tokens for the Bitcorn Game mightbemike 2858 Wed 2019-07-17 Vehicle designer for a space game tuturto 2859 Thu 2019-07-18 HPR NYE Show 2018-2019 part 7 Honkeymagoo 2860 Fri 2019-07-19 Encryption and Quantum Computing Ahuka 2861 Mon 2019-07-22 Safety Razors operat0r 2862 Tue 2019-07-23 Art vs. Commerce In Storytelling lostnbronx 2863 Wed 2019-07-24 Simplified application architectures for improved security Beeza 2864 Thu 2019-07-25 One weird trick to add a --help option to your awk scripts klaatu 2865 Fri 2019-07-26 The YouTube channels I really like Jeroen Baten 2866 Mon 2019-07-29 Intro to Bitcoin for techies mightbemike 2867 Tue 2019-07-30 The Kenwood TS940S Automatic Tuning Unit MrX 2868 Wed 2019-07-31 Custom data with Persistent tuturto Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 13 comments in total.

Past shows

There are 2 comments on 2 previous shows:

hpr2787 (2019-04-09) "NodeJS Part 1" by operat0r. Comment 2: operat0r on 2019-07-09: "Part2 ?"
hpr438 (2009-09-05) "Podcasts I Listen To" by Dave Yates. Comment 1: Viper on 2019-07-03: "Archive of podcasts"
This month's shows

There are 11 comments on 4 of this month's shows:

hpr2851 (2019-07-08) "An introduction to the work of fire fighters" by Jeroen Baten. Comment 1: Ken Fallon on 2019-07-08: "Cars parked over the put"Comment 2: Kevin O'Brien on 2019-07-08: "I loved the show"
hpr2852 (2019-07-09) "Gnu Awk - Part 16" by Dave Morriss. Comment 1: tuturto on 2019-07-09: "thanks"Comment 2: Hipstre on 2019-07-09: "Thank You!"Comment 3: norrist on 2019-07-09: "HPR Epic"Comment 4: Dave Morriss on 2019-07-13: "Many thanks for the kind words"
hpr2854 (2019-07-11) "Telling myself something In The Morning" by Jezra. Comment 1: tuturto on 2019-07-11: "Bagpipes for the win!"Comment 2: Dave Beck on 2019-07-18: "Rusted Pipes"Comment 3: jezra on 2019-07-18: "pipes up!"
hpr2859 (2019-07-18) "HPR NYE Show 2018-2019 part 7" by Honkeymagoo. Comment 1: dodddummy on 2019-07-29: "I disagree with just about all the opinions expressed in this episode."Comment 2: dodddummy on 2019-07-29: "1st hour, that is."
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-July/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Ohio LinuxFest Conference CFP

From Susan Rose, Social Media Manager for OLF:

Dear Open Source Fans, Students and Professionals:

The 2019 Ohio LinuxFest is looking for presentations on Friday and Saturday, November 1 and 2. Please visit the CFP page https://ohiolinux.org/call-for-presentations/ for full details about submitting a proposal. The deadline is Friday, August 17, but the sooner you can submit a talk, the better.

Started in 2003, the Ohio LinuxFest https://ohiolinux.org/ is an annual grassroots conference in Columbus, Ohio dedicated to open access for all. Presentations relating to any free and open source software, not just Linux, are welcome. Areas where we’ve had talks in the past include networking, system administration, development, and community building. A preliminary pdf brochure is attached.

Our audience consists of people at all skill levels. Prior speaking experience is a plus, although we do try to provide opportunities for first-time speakers. If you have any questions, please contact us at speakers@ohiolinux.org. We look forward to hearing from you! Thank you for your kind attention and for sharing.

The PDF Brochure mentioned is available at http://hackerpublicradio.org/eps/hpr2871/olf2019.pdf.

Problem with show 2855

We upload all HPR shows to the Internet Archive (archive.org). Shows downloaded via the HPR RSS feeds actually come from there, though they are also available on the HPR site.

Unfortunately, on Friday July 12th the archive.org copy of the show hpr2855 :: HPR NYE Show 2018-2019 part 6 was found to have been truncated and to consist only of the introduction and final part; no actual content.

The problem was detected during the morning of Friday and was rectified during the afternoon (UK time). The RSS feeds were adjusted to ensure the show was re-downloaded and all podcatchers should have received the correct version the next time they checked the feed.

Tags and Summaries

Thanks to the following contributor for sending in updates in the past month: Dave Morriss

Over the period tags and/or summaries have been added to 11 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2870: Hierarchy of Evidence

Aug 2, 2019


The idea of a Hierarchy of Evidence is that there is a ranking of studies of different kinds in terms of how persuasive they are. It is not enough to simply say that “A study shows…” without also looking at what kind of study it is how powerful the results are. We look at the different kinds of studies and rank them from top to bottom.

Links https://en.wikipedia.org/wiki/Hierarchy_of_evidence https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2707010/ http://www.phru.nhs.uk/casp/rcts.htm https://en.wikipedia.org/wiki/Cohort_study https://en.wikipedia.org/wiki/Framingham_Heart_Study https://en.wikipedia.org/wiki/Case-control_studies https://en.wikipedia.org/wiki/Cross-sectional_study https://en.wikipedia.org/wiki/Case_reports https://www.palain.com/?page_id=402

HPR2869: building a bike, following in John Kulp's footsteps

Aug 1, 2019

HPR2868: Custom data with Persistent

Jul 31, 2019


Podcast episode is about two things, serializing custom data with Persistent and IsString typeclass.

I’m using Persistent in conjunction with Yesod (web framework). Process in short is that data is defined in /config/models file that is used in compile time to generate data type definitions for Haskell. Same information is used to create schema for the database when Yesod application starts. It can even do simple migrations if schema changes, but I wouldn’t recommend using that in production.

Persistent maps information between database and program written in Haskell. There’s pre-existing mappings for things like text and various kinds of numbers. In case one wants to use custom data type, compiler can automatically generate needed mapping. This automatic generation works well with enumerations and very complex data.

For example, following piece defines enumeration BuildingType that is mapped in varchar field in database. Enumeration is thus stored as text.

data BuildingType = SensorStation | ResearchComplex | Farm | ParticleAccelerator | NeutronDetector | BlackMatterScanner | GravityWaveSensor deriving (Show, Read, Eq) derivePersistField "BuildingType"

For newtypes, automatic deriving works too, but generates (in my opinion) extra information that isn’t needed. This extra information causes data saved as text. For those cases, manual mapping can be used.

Our example is for StarDate, which is just glorified Int. I’m using newtype to make StarDate distinct from any other Int, even when it behaves just like Int.

newtype StarDate = StarDate { unStarDate :: Int } deriving (Show, Read, Eq, Num, Ord) instance PersistField StarDate where toPersistValue (StarDate n) = PersistInt64 $ fromIntegral n fromPersistValue (PersistInt64 n) = Right $ StarDate $ fromIntegral n fromPersistValue _ = Left "Failed to deserialize" instance PersistFieldSql StarDate where sqlType _ = SqlInt64

One more trick, that doesn’t directly relate to Persistent is IsString type class. Instead of having to specify all the time what type text literal is, one can let compiler to deduce it from usage.

For example, if I had a newtype like:

newtype PlanetName = PlanetName { unPlanetName :: Text }

I can turn on OverloadedStrings pragma and create IsString instance:

instance IsString PlanetName where fromString = PlanetName . fromString

Now I can write: placeName = "Earth" instead of placeName = PlanetName "Earth" and compiler can deduce correct type based on how the placeName is used.

Thanks for listening, if you have any questions or comments, you can reach me via email or in the fediverse, where I’m tuturto@mastodon.social.

HPR2867: The Kenwood TS940S Automatic Tuning Unit

Jul 30, 2019


In this episode I let you hear the operation of my Kenwood TS940S automatic tuning unit. It had been a while since I’d last transmitted and I was a bit nervous that it might not even work – apparently it still does.

Link to my original show that had a comment from Michael
hpr2668 :: Explaining the controls on my Amateur HF Radio Part 3

Link to article about the Kenwood TS940-S

Information on the Automatic Tuning Unit located internally within the Kenwood TS940S apparently its an optional Unit with Part number AT-940

if you really want to dive into more detail about Tuning units feel free to follow this link in wikipedia.

Dipole information from wikipedia

40M band allocation information from Wikipedia

Noise Blanker information from wikipedia

HPR2866: Intro to Bitcoin for techies

Jul 29, 2019


This is a broad introduction to Bitcoin from a technical perspective. We do not talk about finance or economics, and we don’t compare distributed ledger technologies. We’re not addressing exchanges, layer 2 technologies, mainstream adoption, etc.

We’re also going to avoid going deep into forks, fungibility, mining or the math of Bitcoin.

In this episode we introduce these fundamental Bitcoin topics:

What is Bitcoin? Blockchains and blocks What are transactions? What are miners and what do they do? Proof of Work in Bitcoin - SHA256 hashing Bitcoin consensus mechanism How do wallets work? Brief discussion about various types of wallets and wallet security

I hope this is accessible and informative and look forward to doing more in the future.

HPR2865: The YouTube channels I really like

Jul 26, 2019


The Late Show with Stephen Colbert

Apollo AGC Part 1: Restoring the computer that put man on the Moon

Virtual AGC — AGS — LVDC — Gemini


Death Wears Bunny Slippers

HPR2864: One weird trick to add a --help option to your awk scripts

Jul 25, 2019


The first method is in Awk itself.

#!/usr/bin/awk -f # # USAGE EXAMPLE: # echo the input of some var # $ foo -v var=8 # BEGIN { if (length(var) == 0) { printf "%s %sn", ENVIRON["_"], "is a proof-of-concept help message"; printf "%sn", "Usage:"; printf "%sn", "------"; printf "%s %s %sn", "$", ENVIRON["_"], "-v var=NUM"; printf "%sn", "substitute NUM with the number you want echoed"; exit } else { printf "%s %sn", "You have entered ", var; } }

The disadvantage to this is that it only provides a help message if no option is provided. If you actually type --help, then you get Awk's help message, which is not useful in this context.

The shell script wrapper method uses the shell to parse options, which are then passed to an embedded Awk script:

#!/bin/sh if [ "${1}" = "--help" -o "${1}" = "-h" -o "${1}" = "" ]; then echo "This is a help message." exit fi /usr/bin/awk -v var="${1}" ' BEGIN { printf "%s %sn", "You provided", var; }'

The disadvantage here is only that you're not just writing an Awk script, you're writing a shell script with embedded Awk. I can't think of a reason not to do it this way (even though in the script that served as the inspiration for this episode, I don't use this method).

HPR2863: Simplified application architectures for improved security

Jul 24, 2019


Before the days of the PC, application architectures were often very simple - being little more than the executable itself and any input files. The constraints of the early PC’s very limited resources required new architectures to make the most of those resources.

We now have a situation where most applications either install, or require the presence of, multiple runtime dependencies. Each dependency has an interface which allows communication between itself and the application, but every interface presents an attack surface with the potential to be exploited by a malicious 3rd party.

Modern computers do not have those same resource constraints yet we are still developing applications using the principles that applied 3 decades ago.

Re-usable functionality can be internalised through static linking at compile-time or by code inclusion (along the lines of a .h file in C/C++)

To change from using tried and tested methods is never convenient, but with concern for cyber security high and rising, has the time come to exchange convenience for simpler application architectures that should reduce vulnerabilities?

…And may a move to new (or is it old) architectures deliver a big win for open source software?

HPR2862: Art vs. Commerce In Storytelling

Jul 23, 2019


In this final episode of "Random Elements of Storytelling", Lostnbronx looks at the question of art vs. commerce.

When is a story a product? When is it a work of passion? Can it be both? In a era of interactive storytelling, what is the difference between a story teller and an audience? And where do art, commerce, creativity, and consumption intersect?

Lostnbronx wanders over hill and dale, and likely fails to adequately explain anything at all.

HPR2860: Encryption and Quantum Computing

Jul 19, 2019

HPR2859: HPR NYE Show 2018-2019 part 7

Jul 18, 2019


Hacker Public Radio New Years Show episode 7

Welcome to the 7th Annual Hacker Public Radio New Years Show. 2018-2019

Trucking Patrick Stewart and Bret Spiner
https://www.youtube.com/watch?v=EvJ7xR4D1ZI Self Defense The origin of Irish coffee Calendars Sleep The Pine Book
https://www.pine64.org/pinebook/ Guns Tanks AmazFit Bip
https://us.amazfit.com/shop/bip?variant=336750 Canes

HPR2858: Vehicle designer for a space game

Jul 17, 2019


This episode is about modeling vehicle designer that can be used to design all kinds of vehicles available in the game. It relates to episode about performing research.

Major parts

Two major parts about vehicle designer are components and chassis.

Components are modular pieces of vehicle that are assembled on chassis. They can, among other things, be things lie star sails, astrolabe navigators or long range sensor. Each component is defined by two values ComponentId and ComponentLevel. If you know these two values, you’ll be able to find out details of the component. ComponentId tells what component it is and ComponentLevel the general knowledge of it. When component is first discovered as a result of research, it’s just a prototype and as a such doesn’t function particularly well. Further research refines it and factories are able to produce higher quality components.

Full definition of component is show below:

data Component = Component { componentId :: ComponentId , componentLevel :: ComponentLevel , componentName :: ComponentName , componentDescription :: ComponentDescription , componentWeight :: Weight , componentSlot :: ComponentSlot , componentType :: [ ComponentPower ] , componentCost :: RawResources ResourceCost , componentChassisType :: ChassisType } deriving (Show, Read, Eq, Ord)

Two particularly interesting fields are componentSlot and componentType. componentSlot has type of ComponentSlot and defines what kind of slot the component occupies in chassis. As there are limited amount of slots in each chassis, designer needs to make compromises on what components to install. componentType has type of ComponentPower, which defines what component does in general. It could be sensor or provide supplies for the vehicle for example.

Technology requirements are defined by function: componentRequirements :: ComponentId -> Maybe Technology. It defines which technology unlock a given component. Part of the definition is show below. Each and every ComponentId has to be handled.

componentRequirements ShipLongRangeSensors = Just HighSensitivitySensors componentRequirements ShipBridge = Nothing componentRequirements VehicleWheeledMotiveSystem = Nothing componentRequirements VehicleHoverMotiveSystem = Just HoverCrafts ...

Second major part of the designer are chassis. They’re stored in database, as I wanted a bit more flexible system than hardcoding as I did with components. Following piece of configuration is used to define database table and generated data for Haskell code. Most of the fields are probably easy enough to guess. type with type of ChassisType defines if this particular chassis is for example a land vehicle or a space ship. Various slot fields on other hand define amount of particular slots that the chassis offers.

Chassis json name ChassisName tonnage Weight type ChassisType technology Technology Maybe armourSlots SlotAmount innerSlots SlotAmount outerSlots SlotAmount sensorSlots SlotAmount weaponSlots SlotAmount engineSlots SlotAmount motiveSlots SlotAmount sailSlots SlotAmount deriving Show Read Eq

Not all chassis are equal and some (probably pretty much every one of them) have some sort of requirements that has to be fulfilled when designing a vehicle. For example, space ships require a bridge for captain and star sails. Bawley, smallest of the working ships has room for two star sails, but requires only one of them to be installed in order to be a valid design. Flyboat on the other hand is smaller ship built for speed and always requires two set of sails.

This data is stored in required_component table and represented as RequiredComponent data. Both are generated from the definition show below:

RequiredComponent json chassisId ChassisId componentType ComponentType level ComponentLevel amount ComponentAmount deriving Show Read Eq Designing a vehicle

With all that data, we can now design a vehicle. Process is roughly the following:

based on completed research, get a list of chassis that are available select chassis from the list based on the selected chassis and completed research, get a list of components that are available select components to install remember to check that maximum tonnage isn’t exceeded and that there’s enough slots and requirements are met fill in name save into database

Completed design is saved in two different tables. First one design holds info like name of the design, faction that design belongs to and used chassis. planned_component holds info about which components are planned to be installed and in what quantity.

Design json name Text ownerId FactionId chassisId ChassisId deriving Show Read Eq


PlannedComponent json designId DesignId componentId ComponentId level ComponentLevel amount ComponentAmount deriving Show Read Eq

As a little teaser, below is an screenshot of what the vehicle designer currently looks like.

Screenshot of vehicle designer showing chassis and components


Thanks for interest. If you have questions or comments, best way to reach me nowadays is either by email or in fediverse, where I’m tuturto@mastodon.social.

HPR2857: Creating CounterParty Collectible Tokens for the Bitcorn Game

Jul 16, 2019


Bitcorn is an idle farming game created with and played using Bitcoin tokens using the CounterParty protocol. I’ll walk you through how it all works, how to get started and what all that means.

In this episode we’ll walk through the basics of creating and submitting a Bitcorn collectible card to be included in the game, along with setting up a wallet so you can buy and sell them.

HPR2856: Mint Mobile Security Rant

Jul 15, 2019


You can also use call forwarding to forward calls to your google voice number. Mint does not seem to stay connected all the time.

HPR2855: HPR NYE Show 2018-2019 part 6

Jul 12, 2019


Hacker Public Radio New Years Show episode 6

Welcome to the 7th Annual Hacker Public Radio New Years Show. 2018-2019

The Makerz Podcast
https://podnutz.com/category/themakerz/ Tronxy X1
https://all3dp.com/1/tronxy-x1-3d-printer-review/ SBC talk Apple Talk Linux on mobile more 3d printing talk http://www.newmodeus.com/shop/ new years food traditions Cats The Last Centurion
https://www.amazon.com/Last-Centurion-John-Ringo/dp/1439132917 https://www.chewy.com/

HPR2854: Telling myself something In The Morning

Jul 11, 2019


Source for In The Morning: https://gitlab.com/jezra/in-the-morning Bottle Framework: http://bottlepy.org

HPR2853: Feeding the beast

Jul 10, 2019

HPR2852: Gnu Awk - Part 16

Jul 9, 2019



This is the sixteenth and final episode of the 'Learning Awk' series which is being produced by b-yeezi (BY) and Dave Morriss (DM).

We are using this as an opportunity to have a round-table discussion about the series, about Awk, and where we recommend the listeners should go from here. Including this one we have produced 16 episodes covering the features most likely to be used in pipelines on the command line or in simple shell and awk scripts.

Note that although the HPR site will list this episode as having a single host, in fact it has two! Plans are afoot to enhance the HPR database so we can eventually indicate this properly.

Topics Discussed The series Started in 2016 (first show released 2016-07-13) Finishing in 2019 16 episodes in total Why are we finishing the series? We have probably reached the limit of what is useful on the command line or in shell scripts or even in manageable-sized Awk scripts Awk shows its limitations as we go on and doesn’t compare well with more modern text processing languages Our personal experiences with Awk BY: Started with sed and awk when first moving to Linux in 2011 (ongoing) Exploring and cleaning client data (ongoing) Personal scripts when adding python or other tool would be overkill DM: Working with VAX/VMS in the 1980’s. No very good text processing features built-in, so Gnu Awk (and sed) was a great way to handle the data we were using to generate accounts for new students each year. Could easily spot bad records, do some data validation (for example impossible dates of birth). Later in the late 1980’s and early 1990’s more Unix systems came on the scene running HP-UX, Ultrix, SunOS, Solaris, OSF/1, True64 Unix, and awk was very much used there. Later still we moved to Linux; initially Fedora but later RHEL, and of course awk figured in the list of tools there as well. What have we left out? Why? User-defined functions are pretty clunky and hard to use Multi-dimensional arrays: other languages do this better Internationalization: assumes you’re writing big awk programs The gawk debugger: quite clever but probably overkill for this series Extensions written in C and C++: some come with gawk and look quite good, but this subject is out of scope What to use as an alternative to Awk? DM moved from gawk to Perl (version 4) in the 1980’s and later to Perl version 5. This might have engendered an awky, Bashy mindset that’s hard to shake off. Not the recommended place to start these days. BY moved from gawk to Python and R for large projects. For interactive Bashy exploration, moved to XSV, q, and csv-kit for most use cases. These tools have built-in convenience features, like accounting for headers, data types, and file encodings What’s next? It is planned to turn the notes for this series into a combined document which will be available on the HPR site and on archive.org. There is no timescale for this at the moment Links GNU Awk User’s Guide Internationalization with gawk A proof that Unix utility sed is Turing complete Mutagen - discussed as an alternative way to access audio metadata (tags) from Python XSV csvkit Run SQL on CSV files with q Links to all of the shows in this series on HPR: Gnu Awk - Part 1 - episode 2114 Gnu Awk - Part 2 - episode 2129 Gnu Awk - Part 3 - episode 2143 Gnu Awk - Part 4 - episode 2163 Gnu Awk - Part 5 - episode 2184 Gnu Awk - Part 6 - episode 2238 Gnu Awk - Part 7 - episode 2330 Gnu Awk - Part 8 - episode 2438 Gnu Awk - Part 9 - episode 2476 Gnu Awk - Part 10 - episode 2526 Gnu Awk - Part 11 - episode 2554 Gnu Awk - Part 12 - episode 2610 Gnu Awk - Part 13 - episode 2804 Gnu Awk - Part 14 - episode 2816 Gnu Awk - Part 15 - episode 2824 Gnu Awk - Part 16 - episode 2852

HPR2851: An introduction to the work of fire fighters

Jul 8, 2019


Some general basic knowledge of fire fighting. Also an invitation to ask questions in the comments.

HPR2850: NIST Cybersecurity Framework

Jul 5, 2019


The National Institute of Standards and Technology of the US Government issued the NIST Cybersecurity Framework, which has recommendations for private companies and mandates for U.S. Government agencies. For people who work in information security in an Enterprise environment, this framework may be of interest, so we will take a walk through it.

Links: https://en.wikipedia.org/wiki/National_Institute_of_Standards_and_Technology https://en.wikipedia.org/wiki/NIST_Cybersecurity_Framework https://nvlpubs.nist.gov/nistpubs/CSWP/NIST.CSWP.04162018.pdf http://www.zwilnik.com/?page_id=997

HPR2849: HPR NYE Show 2018-2019 part 5

Jul 4, 2019


Hacker Public Radio New Years Show episode 5

Welcome to the 7th Annual Hacker Public Radio New Years Show. 2018-2019

Sans Holiday Hack Challenge
https://www.holidayhackchallenge.com/2018/ Hack The Box
https://www.hackthebox.eu/ Over the Wire
http://overthewire.org/wargames/ Under the Wire
http://underthewire.tech/ Gnome Boxes
https://en.wikipedia.org/wiki/GNOME_Boxes Talking about headsets Mobile operating systems Plasma Mobile
https://www.plasma-mobile.org/ Kansas Linux Fest
https://kansaslinuxfest.org/ FreeNas
https://freenas.org/ Talking Desktop Environments GPD mini laptops
https://www.gpd.hk/ Gemini PDA
https://www.indiegogo.com/projects/gemini-pda-android-linux-keyboard-mobile-device--2#/ usb-c
https://en.wikipedia.org/wiki/USB-C Talking uefi
https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface Boxing day
https://en.wikipedia.org/wiki/Boxing_Day UK vs US More Brexit talk
https://www.bbc.com/news/uk-politics-32810887 year 2038 problem
https://en.wikipedia.org/wiki/Year_2038_problem LXQT desktop
https://lxqt.org/ Enlightenment desktop
https://www.enlightenment.org/ gnome boxes

HPR2848: Random numbers in Haskell

Jul 3, 2019


There’s lots of random and similar sounding words in this episode. I hope you can still follow what I’m trying to explain, but I’m aware that it might be hard.

Haskell functions are pure, meaning that they will always produce same values for same set of arguments. This might sound hard when you want to generate random numbers, but it turns out that the solution isn’t too tricky.

First part to the puzzle is type class RandomGen:

class RandomGen g where next :: g -> (Int, g) genRange :: g -> (Int, Int) split :: g -> (g, g)

next produces tuple, where first element is random Int and second element is new random generator. genRange returns tuple defining minimum and maximum values this generator will return. split produces tuple with two new random generators.

Using RandomGen to produce random values of specific type or for specific range requires a bit of arithmetic. It’s easier to use Random that defines functions for that specific task:

class Random a where randomR :: RandomGen g => (a, a) -> g -> (a, g) random :: RandomGen g => g -> (a, g) randomRs :: RandomGen g => (a, a) -> g -> [a] randoms :: RandomGen g => g -> [a] randomRIO :: (a, a) -> IO a randomIO :: IO a randomR, when given range and random generator, produces tuple with random number and new generator random, is similar but doesn’t take range. Instead it will use minimum and maximum specific to that data type randomRs, takes range and produces infinite list of random values within that range randoms, simply produces infinite list of random values using range that is specific to datatype randomRIO and randomIO are effectful versions that don’t need random generator, but use some default one

In short, RandomGen is source of randomness and Random is datatype specific way of generating random values using random generator RandomGen.

Final part of the puzzle is where to get RandomGen? One could initialize one manually, but then it wouldn’t be random. However, there’s function getStdGen that will seed RandomGen using OS default random number generator, current time or some other method. Since it has signature of getStdGen :: IO StdGen, one can only call it in IO monad.

Functions that operate with IO can only be called from other IO functions. They can call pure functions, but pure functions can’t call them. So there’s two options: have the code that needs random numbers in effectful function or get RandomGen in effectful function and pass it to pure function.

Example import System.Random import Data.List -- | get n unique entries from given list in random order -- | if n > length of list, all items of the list will be returned getR :: RandomGen g => g -> Int -> [a] -> [a] getR g n xs = fmap (xs !!) ids where ids = take (min n $ length xs) $ nub $ randomRs (0, length xs - 1) g -- | Returns 4 unique numbers between 1 and 10 (inclusive) test :: IO [Int] test = do g <- getStdGen return $ getR g 4 [1..10] In closing

Pseudo randomness doesn’t require IO, only seeding the generator does. Simple computation that don’t require many calls to random are easy enough. If you need lots of random values, MonadRandom is better suited. It takes care of carrying implicit RandomGen along while your computation progresses.

Best way to catch me nowadays is either email or fediverse where I’m tuturto@mastodon.social

HPR2847: earbuds

Jul 2, 2019


operat0r discusses his trials with earbuds and custom setups.

HPR2846: HPR Community News for June 2019

Jul 1, 2019


table td.shrink { white-space:nowrap } New hosts

Welcome to our new host:
Shannon Wright.

Last Month's Shows Id Day Date Title Host 2826 Mon 2019-06-03 HPR Community News for May 2019 HPR Volunteers 2827 Tue 2019-06-04 Unscripted ramblings from my garage about my first CTF event Christopher M. Hobbs 2828 Wed 2019-06-05 Writing Web Game in Haskell - Science, part 2 tuturto 2829 Thu 2019-06-06 Discussion around fair use clips on HPR Various Hosts 2830 Fri 2019-06-07 HPR NYE Show 2018-2019 part 1 Honkeymagoo 2831 Mon 2019-06-10 Interview with Robbie Ferguson Yannick 2832 Tue 2019-06-11 How I got started in Linux Shannon Wright 2833 Wed 2019-06-12 Jeroen chats with Joep Piscaer Jeroen Baten 2834 Thu 2019-06-13 My favorite desktop and android applications Christopher M. Hobbs 2835 Fri 2019-06-14 HPR NYE Show 2018-2019 part 2 Honkeymagoo 2836 Mon 2019-06-17 Interview with Wendy Hill Yannick 2837 Tue 2019-06-18 parallax live desktops in android operat0r 2838 Wed 2019-06-19 Why Haskell? tuturto 2839 Thu 2019-06-20 Sample episode of the Distrohoppers Digest podcast Ken Fallon 2840 Fri 2019-06-21 HPR NYE Show 2018-2019 part 3 Honkeymagoo 2841 Mon 2019-06-24 How I got into Linux (and then some...) Christopher M. Hobbs 2842 Tue 2019-06-25 What's in my Bag an update to hpr2065 Tony Hughes AKA TonyH1212 2843 Wed 2019-06-26 Afrikan Tähti (or Star of Africa) tuturto 2844 Thu 2019-06-27 The Sony TC-222-A Portable Reel-To-Reel Tape Recorder Jon Kulp 2845 Fri 2019-06-28 HPR NYE Show 2018-2019 part 4 Honkeymagoo Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 19 comments in total.

Past shows

There is 1 comment on 1 previous show:

hpr2807 (2019-05-07) "Are bash local variables local?" by clacke. Comment 1: Dave Morriss on 2019-06-06: "Thanks for this"
This month's shows

There are 18 comments on 8 of this month's shows:

hpr2827 (2019-06-04) "Unscripted ramblings from my garage about my first CTF event" by Christopher M. Hobbs. Comment 1: Christopher M. Hobbs on 2019-05-30: "event cancellation"Comment 2: tuturto on 2019-06-04: "sorry to hear about cancellation"
hpr2829 (2019-06-06) "Discussion around fair use clips on HPR" by Various Hosts. Comment 1: Joel D on 2019-06-06: "Fair Use"Comment 2: Ken Fallon on 2019-06-07: "We don't know"
hpr2830 (2019-06-07) "HPR NYE Show 2018-2019 part 1" by Honkeymagoo. Comment 1: folky on 2019-06-10: "plumble is better than I thought."Comment 2: folky on 2019-06-10: "More %"Comment 3: Dave Morriss on 2019-06-10: "Missing '%' in date command"
hpr2831 (2019-06-10) "Interview with Robbie Ferguson" by Yannick. Comment 1: b-yeezi on 2019-06-10: "Just what I was looking for "
hpr2832 (2019-06-11) "How I got started in Linux" by Shannon Wright. Comment 1: NYbill on 2019-06-11: "Welcome!"
hpr2833 (2019-06-12) "Jeroen chats with Joep Piscaer" by Jeroen Baten. Comment 1: Ahuka on 2019-06-14: "Great show!"
hpr2837 (2019-06-18) "parallax live desktops in android" by operat0r. Comment 1: norrist on 2019-06-18: "I like this kind of episode."
hpr2839 (2019-06-20) "Sample episode of the Distrohoppers Digest podcast" by Ken Fallon. Comment 1: Mike Ray on 2019-06-20: "Accessibility"Comment 2: Bob on 2019-06-20: "reply to Mike"Comment 3: Mike Ray on 2019-06-20: "Accessibility and non-English character sets"Comment 4: Tony Hughes on 2019-06-21: "Responce to Mike and Bob"Comment 5: Bob on 2019-06-23: "I wasn't serious"Comment 6: Mike Ray on 2019-06-25: "Accessibility"Comment 7: TonyH1212 on 2019-06-29: "Further responce to Mike and Bob"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-June/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Issue with advanced RSS settings

The page at http://www.hackerpublicradio.org/advanced_rss_settings.php describes a series of features that allow the specification of a tailored RSS feed.

One of the features is 'gomax=1' which includes shows in the queue scheduled for the future. For example, the following URL requests 30 OGG format shows including those scheduled for the future:


However, there is a problem with this, caused by the way we direct downloads to archive.org. We usually upload the next week’s shows to archive.org, but not all future shows as they arrive. This means that the links to some future shows returned by the feed point to currently non-existent episodes.

This has been the case ever since we moved to using archive.org in this way, in late 2017. We have not received any comments or complaints about it in that time, so the question is:

Does anyone use 'gomax=1'?

Tags and Summaries

Thanks to the following contributor for sending in updates in the past month: Tony Hughes

Over the period tags and/or summaries have been added to 6 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2845: HPR NYE Show 2018-2019 part 4

Jun 28, 2019


Hacker Public Radio New Years Show episode 4

Welcome to the 7th Annual Hacker Public Radio New Years Show. 2018-2019

3D Printing OSMC
https://osmc.tv/ Anet A8
https://3dprint.wiki/reprap/anet/a8 Dell Venue 11 pro 7130
https://www.cnet.com/products/dell-venue-11-pro/specs/ http://www.studioteabag.com/science/dell-venue-pro-linux/DV11P/ Drag vape
http://en.voopootech.com/drag-param Gigabyte Brix
https://www.gigabyte.com/us/Mini-PcBarebone SDR talk DSP hack a day
https://hackaday.com/tag/dsp/ Mastodon
https://joinmastodon.org/ hpr 2627 Home phone setup
http://hackerpublicradio.org/eps.php?id=2627 Asterisk
https://en.wikipedia.org/wiki/Asterisk_(PBX) Hanging LED lights The Wall Clipper chip
https://en.wikipedia.org/wiki/Clipper_chip Podcasting Time zones yet again Firearms President Trump Linux action news
https://linuxactionnews.com/ Late night Linux
https://latenightlinux.com/ User error

HPR2844: The Sony TC-222-A Portable Reel-To-Reel Tape Recorder

Jun 27, 2019


In this episode I talk about my new 1969 Sony TC-222-A portable reel-to-reel tape recorder. I found it about 3 weeks ago at Hand-Up Thrift store in Lafayette Louisiana for $5. It was in partially working condition, without a power cord, and in need of some work. I cleaned the contact points, overhauled the fast-forward idler wheel, lubricated both of the tape shafts, replaced the belts, hacked an old electric razor cord to work as a power cord, and tightened up the record linkage. One thing I still can't get working is recording using the microphone.

I spend about half of this episode talking about trying to make a super-long recording fit on a 5-inch reel and playing at 4.8 cm/second. I use Kimiko Ishizaka's wonderful Open Goldberg Variations and Open Well-Tempered Clavier as the music. To do this, I speeded up all of the tracks to play at 4x speed, for which I use the following script to loop through all mp3s in the current directory and subject them to the appropriate sox command:

#!/bin/bash for i in *.mp3; do # speed em up 4x infile=$(basename $i) stem=$(basename "$i" .mp3) outfile="$stem"_4x.mp3 sox $infile $outfile speed 4.0 sleep .1 done

It worked! Well. The script and sox command worked. Recording the 4x-speed audio at 19 cm/second and then playing back at 4.8 cm/second also mostly worked, I just had a very poor-quality tape so it sounded pretty bad. The speed was just about right, though. In fact when I compared pitch against my piano, it was EXACTLY right. I may try again with a better tape. (BTW I said my tape was "old new stock," but obviously I meant "new old stock.")

Photo Album (click image)

Sony TC-222-A Portable Reel-to-Reel Tape Recorder

Links Video: The Sony TC-222-A in action Techmoan: one of my favorite YouTube channels Music bumpers are from Kimiko Ishizaka's The Open Goldberg Variations: http://www.opengoldbergvariations.org/, used by permission of their CC0 1.0 Universal (CC0 1.0) Public Domain Dedication license. Vintage Electronics, my source for replacement belts, replacement lamps for my Marantz receiver, etc.

HPR2843: Afrikan Tähti (or Star of Africa)

Jun 26, 2019


For more information about the game and history behind it, have a look at the following links:

Wikipedia: https://en.wikipedia.org/wiki/Afrikan_t%C3%A4hti Board Game Geek: https://www.boardgamegeek.com/boardgame/5130/afrikan-tahti

HPR2842: What's in my Bag an update to hpr2065

Jun 25, 2019


Hello HPR land, this is Tony Hughes again coming to you from Blackpool in the UK.

During my last episode, which was my 50th for HPR, I realized that my ‘Bag’ has changed considerably since recording my episode hpr2065 about it back in July 2016. So this is an update on what I currently carry in my ‘Geek’ Bag when out and about.

I have several laptops which are used for different things at different times so may or may not be in the bag/bags depending on what I am doing. This is the list:

Lenovo X230i Toshiba z30 Dells E6220 x 2, E7250, E7440 and E6540

Recently I have moved more to Dell laptops and the Dell E7440 is a great compromise of portability and usability with its 14" 1080p screen, but if I want light and long battery life the Toshiba z30 is a fantastic little PC with all day battery life and a great 13.3" screen.

But all the others have their place in the bag, for demonstrating Linux Distros at events or at my LUG.

So the next thing that makes it into the bag is my ZoomH2 recorder that goes with me for recording interviews at events I attend, with the intention of producing HPR shows.

I also have some tools, the first is a little set of a screwdriver and small driver bits made by Draper this is handy for laptop tear downs as it has all the necessary bit heads needed to work on electronics. I also carry a small set of pliers and a wire cutter in the bag.

I also carry a 10000mA battery pack for charging my mobile phone if needed while out and about. In conjunction with this a I carry several micro USB charging cables and a USB C cable for the increasing number of USB C devices around these days.

In the bag are also a couple of 128Gb SSD’s as spares for quick swap outs, if I don’t want to wipe a drive but wish to test a new OS, or for those times the only solution to helping someone rescue an older laptop is to stick an SSD into it.

I generally carry my 1Tb portable USB3 HDD around with me as I store a large number of current Linux ISO files for burning to a flash drive to create boot discs. With that it goes without saying that I have a few spare flash drives in the bag for just this use. I also usually carry a few SD cards for creating Raspberry Pi images if needed.

Other items include a USB WiFi card as a backup if I have a WiFi malfunction, or I’m working on a machine without its own WiFi card.

Well that’s about it for what I’m currently carrying in my bag, but before I go a bit of sad news. Many of you have heard me talk of my latest bargains from the Computer Auction I have frequented since 2006. Well sadly NO MORE, Northern Realisations after 20 years of trading have closed their doors for the last time, so I need to find another source of cheap PC equipment. As they say: All good things come to an end.

Well that’s it for this episode, this is Tony Hughes signing off for Hacker Public Radio.



HPR2841: How I got into Linux (and then some...)

Jun 24, 2019


Basically what it says on the tin. Most distros I mention can be easily searched for. I meander through a discussion of how I got into Linux and where I am with it now.

HPR2840: HPR NYE Show 2018-2019 part 3

Jun 21, 2019

HPR2839: Sample episode of the Distrohoppers Digest podcast

Jun 20, 2019


This is a sample episode of the new Creative Commons tech podcast. It's brought to us by Moss and our own Tony Hughes. From the blurb:

We are two Blokes who love Linux and trying out new stuff, we thought it would be interesting to share our experience of trying new Linux and BSD distributions and how we found it trying to live with them as our daily driver for up to a Month at a time, by recording a podcast about how we got on. Links https://distrohoppersdigest.blogspot.com/ https://distrohoppersdigest.blogspot.com/feeds/posts/default https://distrohoppersdigest.blogspot.com/feeds/posts/default?alt=rss http://hackerpublicradio.org/correspondents.php?hostid=338 https://mintcast.org/

HPR2838: Why Haskell?

Jun 19, 2019


I got really good comment on episode 2778 - Functor and applicative in Haskell from Beeza that I’m including below:

I’ve been writing software for over 30 years but I find the syntax of Haskell anything but intuitive - in fact less so than any other programming language I have looked at. Thanks to your excellent show notes I can make sense of it but I have to say I would not like to have to develop a project using this language.

Obviously I am missing the point as nobody would design a language with the intention of its being difficult to use. Perhaps you could produce another episode addressing the question “Why Haskell?”

In this episode, I’m trying to answer to that from my point of view.

HPR2837: parallax live desktops in android

Jun 18, 2019


parallax live desktops in android

linkedin Cafinee.exe MouseGiggler espresso autohotkey

Systemd linkedin

linkedin youtube in background
Viewers can download


HPR2836: Interview with Wendy Hill

Jun 17, 2019


Wendy Hill is a photographer. And by that, I don’t mean she takes pictures of her kids on Sundays at the baseball game. Although, if she was to do that, it would probably turn out to be great pictures. No, Wendy is a professional photographer, and to run her business, she uses free and opensource software.

Wait… no Photoshop? No Illustrator? How is that possible? Wendy joined me on Mumble earlier this year – that’s 2019 for you, visitors from the future – and we discussed about that.

Links https://www.wendyhillphoto.com/ https://launchpad.net/lubuntu

HPR2835: HPR NYE Show 2018-2019 part 2

Jun 14, 2019


Hacker Public Radio New Years Show episode 2 Claudio talks about doing IT for a school Pinebook discussion - complaints about keyboard, speakers, trackpad
https://www.pine64.org Scanning photo negatives Camera discussion Firefly
https://www.imdb.com/title/tt0303461 Serenity
https://www.imdb.com/title/tt0379786 Babylon 5
https://www.imdb.com/title/tt0105946 POLYBIUS - The Video Game That Doesn't Exist
https://en.wikipedia.org/wiki/Polybius Cicada 3301
https://en.wikipedia.org/wiki/Cicada_3301 Ahoy you channel
https://www.youtube.com/channel/UCE1jXbVAGJQEORz9nZqb5bQ Resilo Sync
https://en.wikipedia.org/wiki/Resilio_Sync Mintcast
https://mintcast.org/ Zoom H2
https://www.zoom-na.com/products/field-video-recording/field-recording/h2-handy-recorder LG Tone headsets
https://www.lg.com/us/bluetooth-headsets-headphones Urbanite XL
https://en-us.sennheiser.com/urbanite-xl cmhobbs joins and asks for episode input. will record winter field day 2019 from northwest arkansas. Book & audiobook Recommendations for books:
Daemon by Daniel Suarez, http://daniel-suarez.com/ Skyward by Brandon Sanderson, https://brandonsanderson.com/books/skyward/skyward/ Audiobook reading tips:
To get into audiobooks, try listening to a book you've read before Try increasing or decreasing the speed of the book Use the TTS feature of your eBook reader to create your own audiobooks Oddity of TTS mispronouncing words can be fun or frustrating Linux desktop upgrade fun MX Linux
https://mxlinux.org/ AntiX Linux
https://antixlinux.com/ exwm
https://github.com/ch11ng/exwm ZFS on Linux
https://zfsonlinux.org/ Dell venue 11 pro
https://www.dell.com/en-us/work/shop/cty/venue-11-pro/spd/dell-venue-11-pro Acer aspire 1

HPR2834: My favorite desktop and android applications

Jun 13, 2019



xfce4-terminal globaltime (orage) xfce4 notes thunar firefox Emacs claws-mail weechat mupdf gtk-redshift asunder keepassx lucky backup virtualbox/kvm xlog gpredict arduino ide tor browser bundle ledger wallet xmame freedoom rRootage dia fbreader gnumeric/libreoffice mandelbulber2 gqrx transmission xastir youtube-dl gui zenmap mpv


LineageOS built in phone signal built in fm radio built in camera 2048 acrylic paint amsatdroid free antennapod aprsdroid audiofx barcode scanner binaural beats blockinger blowtorch built in calendar call recorder chroma doze built in clock cloudlibrary built in contacts danmaku death echolink equate f-droid fbreader fennec f-droid red cross first aid flashlight freegal music gadgetbridge built in gallery ghost commander gobandroid hoopla iz2uuf morse code trainer libby lightning mobilinkd tnc mupdf netguard o’reilly orbot, orfox osmand~ red cross pet first aid plumble propel graviton radiodroid (radio-browser.info) recorder roblox rpn sealnote sim card simple world clock space trader spotify suntimes, suntimes alarms survival manual termux timber tsumego pro ttrss-reader unifi vlc webtube weechat-android wifianalyzer wikipedia yalp store yorecast

HPR2833: Jeroen chats with Joep Piscaer

Jun 12, 2019


In this show an Interview with Joep Piscaer, recorded during the recent Loadays conference in Antwerpen, Belgium.

Schedule of recent Loadays event: https://cfp.loadays.org/2019/schedule/

I mention the "Cut the crap podcast", made by Ryan Caligiuri.

And specifically episode 145 as an excellent example of his podcast quality:


At the end of the podcast I a refer to the "Follow your Gift" talk, by Steve Harvey.

You can find a recording of this talk on YouTube at https://www.youtube.com/watch?v=3x3rEg2qvcQ

HPR2832: How I got started in Linux

Jun 11, 2019


This is just a brief intro into my introduction to Linux.

HPR2831: Interview with Robbie Ferguson

Jun 10, 2019


When it comes to monitoring your network, and the machines on it, you have a lot of options. But, let’s face it : none of those are easy to implement, and configuring a monitoring tool, whether it’s an open-source or a proprietary one, is often complex and time consuming.

Well, someone took that matter into their own hands, and made NEMS. What is NEMS, how can it help us, and what infrastructure does it require? Those are a few of the questions I asked Robbie Ferguson, the maintainer of NEMS, who joined me on Easter week-end for a little chat.

Links https://nemslinux.com/ https://twitter.com/NEMSLinux https://baldnerd.com/

HPR2830: HPR NYE Show 2018-2019 part 1

Jun 7, 2019


Hacker Public Radio New Years Show episode 1

Welcome to the 7th Annual Hacker Public Radio show. It is December the 31st 2018 and the time is 10 hundred hours UTC.

Ken introduces the New year show, gives some history and thanks Kevin Wisher and HonkeyMagoo for organising this. Wondering where Klaatu is, Fifty one fifty talks about his new isp
https://www.blazinghog.com Ken GETS STUCK IN CAPS LOCK
https://wiki.archlinux.org/index.php/Xorg/Keyboard_configuration ISO8601 YYYY-MM-DD https://en.wikipedia.org/wiki/ISO_8601 https://www.hostelworld.com/hosteldetails.php/STF-IYHF-af-Chapman/Stockholm/32555 Honkey is on his way to work $ alias utc='/bin/date -u +%Y-%m-%d_%H-%M-%S%Z_%A' https://www.youtube.com/watch?v=9PfdQod8HTw History Buffs: Tora! Tora! Tora! klaatu joins us, career at Red Hat, IBM takeover, teaching Linux to non-tech people
https://en.wikipedia.org/wiki/Dalton_Plan Computer musems
http://vonhagen.org/collection.html barcamp (yes related to foo)
https://en.wikipedia.org/wiki/BarCamp Oggcamp
https://oggcamp.org/ Mint Cast Podcast
https://mintcast.org/ Brexit

"we should have bought stock"

HPR2829: Discussion around fair use clips on HPR

Jun 6, 2019


Request for comments

Hi All,

Under safe harbor provisions, we as volunteers are usually insulated from any copyright issues that may arise in the shows. "We do not vet, edit, moderate or in any way censor any of the shows on the network, we trust you to do that."

This we got by accident because "This is a long standing tradition arising from the fact that HPR is a community of peers who believe that any host has as much right to submit shows as any other."

In the show notes associated with hpr2829 on 2019-06-06, the host included the following text "For all included materials: If anyone feels they have right to any material in this show please let me know and I will comply."

This violates the HPR upload policy.

"Never include content, for example music, in your show that you do not have permission to redistribute. Try to avoid using any content in your show that can not be redistributed under a Creative Commons Attribution-ShareAlike 3.0 Unported license. If you are redistributing under another Creative Commons License or by arranged permission please make note of the restrictions when you upload your show. We can then signal that, so that others who redistribute HPR content can filter your show out."

As it was clear that they were not in compliance, I contacted the host. The host has been very helpful and has already removed some of the content but commented "There are still 2 audio clips included. I claim I can use them on the basis off fair use principles."

While the host may be correct, if they are not, then it is me and not the host that will be held responsible for posting it. I do not want that responsibility.

Under the current HPR rules I am allowed to reject this submission.

Before I do, I would appreciate as much feedback as possible on this topic so that we can gauge the opinions of the HPR Community as a whole.



The discussion thread remains open and is open to all by joining the Maillist.

HPR2828: Writing Web Game in Haskell - Science, part 2

Jun 5, 2019



Last time we looked how to model technology and research. This time we’ll do some actual research. I’m skipping over some of the details as the episode is long enough as it is. Hopefully it’s still possible to follow with the show notes.

Main concepts that I’m mentioning: Technology allows usage of specific buildings, ship components and such. Research unlock technologies and may have antecedents that has to be completed before the research can be started. Research cost is measure of how expensive a research is in terms of research points, which are produced by different buildings.

Earlier I modeled tech tree as Map that had Technology as keys and Research as values. I realized that this is suboptimal and will replace it at some point in the future.

Server API

There’s three resources that client can connect to. First one is for retrieving list of available research, second one for manipulating current research and last one for retrieving info on how much research points is being produced.

/api/research/available ApiAvailableResearchR GET /api/research/current ApiCurrentResearchR GET POST DELETE /api/research/production ApiResearchProductionR GET Simulation

Simulation of research is done by handleFactionResearch, which does simulation for one faction for a given date. After calculating current research point production and retrieving list of current research, function calculates progress of current researches. Unfinished ones are written back to database, while completed are moved into completed_research table. Final step is updating what research will be available in the next turn.

handleFactionResearch date faction = do production <- totalProduction $ entityKey faction current <- selectList [ CurrentResearchFactionId ==. entityKey faction ] [] let updated = updateProgress production <$> current _ <- updateUnfinished updated _ <- handleCompleted date updated $ entityKey faction _ <- updateAvailableResearch $ entityKey faction return () Research point production

Research points are produced by buildings. So first step is to load all planets owned by the faction and buildings on those planets. Applying researchOutput function to each building yields a list of TotalResearchScore, which is then summed up by mconcat. We can use mconcat as TotalResearchScore is a monoid (I talked about these couple episodes ago).

totalProduction fId = do pnbs <- factionBuildings fId let buildings = join $ fmap snd pnbs return $ mconcat $ researchOutput . entityVal <$> buildings

researchOutput function below uses pattern matching. Instead of writing one function definition and case expression inside of it, we’re writing multiple definitions. Each of them matches building of different type. First example is definition that is used for ResearchComplex, while second one is for ParticleAccelerator. Final case uses underscore to match anything and indicate that we’re not even interested on the particular value being matched. mempty is again from our monoid definition. It is empty or unit value of monoid, which in case of TotalResearchScore is zero points in all research categories.

researchOutput Building { buildingType = ResearchComplex } = TotalResearchScore { totalResearchScoreEngineering = ResearchScore 10 , totalResearchScoreNatural = ResearchScore 10 , totalResearchScoreSocial = ResearchScore 10 } researchOutput Building { buildingType = ParticleAccelerator } = TotalResearchScore { totalResearchScoreEngineering = ResearchScore 15 , totalResearchScoreNatural = ResearchScore 15 , totalResearchScoreSocial = ResearchScore 0 } researchOutput _ = mempty Updating progress

Moving research forward is more complex looking function. There’s bunch of filtering and case expressions going on, but the idea is hopefully clear after a bit of explanation.

updateProgress takes two parameters, total production of research points and current research that is being modified. This assumes that there are only one of each categories of research going on at any given time. If there were more, we would have to divide research points between them by some logic. Function calculates effect of research points on current research and produces a new current research that is the end result.

Perhaps the most interesting part is use of lenses. For example, line entityValL . currentResearchProgressL +~ engResearch $ curr means that curr (which is Entity CurrentResearch) is used as starting point. First we reach to data part of Entity and then we focus on currentResearchProgress and add engResearch to it. This results a completely new Entity CurrentResearch being constructed, which is otherwise identical with the original, but the currentResearchProgress has been modified. Without lenses we would have to do this destructuring and restructuring manually.

updateProgress :: TotalResearchScore ResearchProduction -> Entity CurrentResearch -> Entity CurrentResearch updateProgress prod curr = case researchCategory <$> research of Just (Engineering _) -> entityValL . currentResearchProgressL +~ engResearch $ curr Just (NaturalScience _) -> entityValL . currentResearchProgressL +~ natResearch $ curr Just (SocialScience _) -> entityValL . currentResearchProgressL +~ socResearch $ curr Nothing -> curr where research = Map.lookup (currentResearchType . entityVal $ curr) techMap engResearch = unResearchScore $ totalResearchScoreEngineering prod natResearch = unResearchScore $ totalResearchScoreNatural prod socResearch = unResearchScore $ totalResearchScoreSocial prod

Writing unfinished research back to database is short function. First we find ones that hasn’t been finished by filtering with (not . researchReady . entityVal) and then we apply replace to write them back one by one.

updateUnfinished updated = do let unfinished = filter (not . researchReady . entityVal) updated mapM (\x -> replace (entityKey x) (entityVal x)) unfinished

Handling finished research starts by finding out which ones were actually completed by filtering with (researchReady . entityVal) and their research type with currentResearchType . entityVal. Rest of the function is all about database actions: creating entries into completed_research and adding news entries for each completed research, then removing entries from current_research and available_research.

handleCompleted date updated fId = do let finished = filter (researchReady . entityVal) updated let finishedTech = currentResearchType . entityVal <$> finished insertMany_ $ currentToCompleted date . entityVal <$> finished insertMany_ $ researchCompleted date fId . (currentResearchType . entityVal) <$> finished deleteWhere [ CurrentResearchId <-. fmap entityKey finished ] deleteWhere [ AvailableResearchType <-. finishedTech , AvailableResearchFactionId ==. fId ] Available research

Figuring out what researches will be available for the next turn takes several steps. I won’t be covering random numbers in detail, they’re interesting enough for an episode on their own. It’s enough to know that g <- liftIO getStdGen gets us a new random number generator that is seeded by current time.

updateAvailableResearch starts by loading available research and current research for the faction and initializing a new random number generator. g can be used multiple times, but it’ll always return same sequence of numbers. Here it doesn’t matter, but in some cases it might. getR is helper function I wrote that uses random number generator to pick n entries from a given list. n in our case is hard coded to 3, but later on I’ll add possibility for player to research technologies that raise this limit. newAvailableResearch (we’ll look into its implementation closer just in a bit) produces a list of available research for specific research category. These lists are combined with <> operator and written into database with rewriteAvailableResearch.

updateAvailableResearch fId = do available <- selectList [ AvailableResearchFactionId ==. fId ] [] completed <- selectList [ CompletedResearchFactionId ==. fId ] [] g <- liftIO getStdGen let maxAvailable = ResearchLimit 3 -- reusing same g should not have adverse effect here let engCand = getR g (unResearchLimit maxAvailable) $ newAvailableResearch isEngineering maxAvailable available completed let natCand = getR g (unResearchLimit maxAvailable) $ newAvailableResearch isNaturalScience maxAvailable available completed let socCand = getR g (unResearchLimit maxAvailable) $ newAvailableResearch isSocialScience maxAvailable available completed rewriteAvailableResearch fId $ engCand <> natCand <> socCand

newAvailableResearch is in charge of figuring out what, if any, new research should be available in the next turn. In case where amount of currently available research is same or greater than research limit, empty list is returned, otherwise function calculates candidates and returns them. Logic for that is following:

candidates are research of specific category of those that has been unlock and unresearched unlocked and unresearched are unlocked ones that are in list of known technology unlocked research are ones with antecedents available in tech tree known technology are ones in list of completed research

and complete definition of the function is shown below:

newAvailableResearch selector limit available completed = if ResearchLimit (length specificCategory) >= limit then [] else candidates where specificCategory = filter (availableResearchFilter selector) available candidates = filter (selector . researchCategory) unlockedAndUnresearched unlockedAndUnresearched = filter (\x -> researchType x `notElem` knownTech) unlockedResearch unlockedResearch = filter (antecedentsAvailable knownTech) $ unTechTree techTree knownTech = completedResearchType . entityVal <$> completed availableResearchFilter f x = maybe False (f . researchCategory) res where res = Map.lookup (availableResearchType $ entityVal x) techMap

Final step of the simulation of research is to update database with new available research. mkUniq is helper function that removes duplicate elements from a list. It’s used in rewriteAvailableResearch function to make a list that contains all unique top research categories (engineering, natural sciences and social sciences). If the resulting list isn’t empty, we’ll use it to remove all available research for those top categories and insert new available research.

rewriteAvailableResearch fId res = do let cats = mkUniq $ fmap (topCategory . researchCategory) res unless (null cats) $ do deleteWhere [ AvailableResearchFactionId ==. fId , AvailableResearchCategory <-. cats ] insertMany_ $ researchToAvailable fId <$> res

Now everything is ready for next round of simulation.

HPR2827: Unscripted ramblings from my garage about my first CTF event

Jun 4, 2019


Unscripted ramblings about an upcoming CTF event. Hak5 items mentioned (hak5.org): WiFi Pineapple Bash Bunny (erroneously referred to as a ‘rabbit’) USB Rubber Ducky Packet Squirrel LAN Turtle (unmentioned but I’ll bring one) Software mentioned: MetaSploit: metasploit.com Ronin: ronin-ruby.github.io Maltego: www.paterva.com/web7/ Burpsuite: portswigger.net/burp/ SET: trustedsec.com/social-engineer-toolkit-set/ Parrot Linux: parrotsec.org My info: Chat with us on irc.freenode.net in #manor More info at https://manor.space My little business: https://ascia.tech Email: cmhobbs@member.fsf.org 1200 0808 F968 47AB F489 91A3 FE26 6FFB 1A77 0868 Other shows by me (in case this one doesn’t get linked) http://hackerpublicradio.org/correspondents.php?hostid=241 Links CTF: Capture the flag; Wikipedia disambiguation page Cyber-security challenge

HPR2826: HPR Community News for May 2019

Jun 3, 2019


table td.shrink { white-space:nowrap } New hosts

Welcome to our new hosts:
Joel D, Zen_Floater2.

Last Month's Shows Id Day Date Title Host 2803 Wed 2019-05-01 Update on my Raspi 3 B OpenMedia Vault and Next Cloud instances JWP 2804 Thu 2019-05-02 Awk Part 13: Fix-Width Field Processing b-yeezi 2805 Fri 2019-05-03 My 50th Show Tony Hughes AKA TonyH1212 2806 Mon 2019-05-06 HPR Community News for April 2019 HPR Volunteers 2807 Tue 2019-05-07 Are bash local variables local? clacke 2808 Wed 2019-05-08 Haskell function types tuturto 2809 Thu 2019-05-09 The Blue Oak Model License and Its One Big Gotcha Joel D 2810 Fri 2019-05-10 Wi-Fi on Android Ken Fallon 2811 Mon 2019-05-13 Interview with Alan Pope Yannick 2812 Tue 2019-05-14 Is 5G mobile data a danger to your health? clacke 2813 Wed 2019-05-15 Should we dump the linux Desktop. knightwise 2814 Thu 2019-05-16 Spectre and Meltdown and OpenBSD and our future Zen_Floater2 2815 Fri 2019-05-17 Copy pasta klaatu 2816 Mon 2019-05-20 Gnu Awk - Part 14 Dave Morriss 2817 Tue 2019-05-21 Are you successful? Click to find out more! clacke 2818 Wed 2019-05-22 Writing Web Game in Haskell - Science, part 1 tuturto 2819 Thu 2019-05-23 Reply to Knightwise - podcasts Ahuka 2820 Fri 2019-05-24 29 - CERT Home Security Tips Ahuka 2821 Mon 2019-05-27 Interviewing some exhibitors at the 2019 vcfe.org event Jeroen Baten 2822 Tue 2019-05-28 What's in the Box! Part 1 NYbill 2823 Wed 2019-05-29 Gentoo and why I use it aldenp 2824 Thu 2019-05-30 Gnu Awk - Part 15 Dave Morriss 2825 Fri 2019-05-31 More text to speech trials Ken Fallon Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 16 comments in total.

Past shows

There are 6 comments on 4 previous shows:

hpr2504 (2018-03-08) "Intro to Git with pen and paper" by klaatu. Comment 1: Ken Fallon on 2019-05-23: "This needs to be a video"
hpr2793 (2019-04-17) "bash coproc: the future (2009) is here" by clacke. Comment 2: clacke on 2019-05-04: "Re: backquotes vs dollar-paren" Comment 3: clacke on 2019-05-09: "Re: awk coprocesses" Comment 4: Dave Morriss on 2019-05-09: "Regarding awk coprocesses"
hpr2794 (2019-04-18) "Interview with Martin Wimpress" by Yannick. Comment 1: Klaatu on 2019-05-26: "Great interview"
hpr2798 (2019-04-24) "Should Podcasters be Pirates ?" by knightwise. Comment 4: Klaatu on 2019-05-07: "This is one of those episodes..."
This month's shows

There are 10 comments on 4 of this month's shows:

hpr2806 (2019-05-06) "HPR Community News for April 2019" by HPR Volunteers. Comment 1: clacke on 2019-05-09: "Yggdrasil and Hollywood"Comment 2: clacke on 2019-05-09: "HKOSCON2019"
hpr2809 (2019-05-09) "The Blue Oak Model License and Its One Big Gotcha" by Joel D. Comment 1: norrist on 2019-05-09: "The show _was_ fun"Comment 2: Joel D on 2019-05-16: "re: norrist"
hpr2813 (2019-05-15) "Should we dump the linux Desktop." by knightwise. Comment 1: Yannick on 2019-05-15: "Should we dump Windows? "Comment 2: Hipstre on 2019-05-15: "Do We Need Linux?"Comment 3: DV on 2019-05-16: "Response to knightwise"Comment 4: DeepGeek on 2019-05-17: "Desktop is Dead"Comment 5: Snapdeus on 2019-05-17: "Linux desktop"
hpr2814 (2019-05-16) "Spectre and Meltdown and OpenBSD and our future" by Zen_Floater2. Comment 1: ClaudioM on 2019-05-17: "Hello, Fellow Puffy Disciple!"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-May/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business Links https://ohshitgit.com/ https://www.nporadio1.nl/podcasts/hallo-hier-hilversum Tags and Summaries

Over the period tags and/or summaries have been added to 10 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2825: More text to speech trials

May 31, 2019


A supplementary show to Jeroens episode HPR2792 :: Playing around with text to speech synthesis on Linux.

I found two addional options. The first is mimic

# dnf info mimic Summary : Mycroft's TTS engine URL : https://mimic.mycroft.ai/ License : BSD Description : Mimic is a fast, lightweight Text-to-speech engine developed by Mycroft A.I. : and VocalID, based on Carnegie Mellon University’s FLITE software. Mimic takes : in text and reads it out loud to create a high quality voice. Mimic's : low-latency, small resource footprint, and good quality voices set it apart : from other open source text-to-speech projects.

And the second is gTTS which is a interface to the google TTS api.

HPR2824: Gnu Awk - Part 15

May 30, 2019



This is the fifteenth episode of the “Learning Awk” series which is being produced by b-yeezi and myself.

This is the second of a pair of episodes looking at redirection in Awk scripts.

In this episode I will spend some time looking at the getline command used for explicit input (as opposed to the usual implicit sort), often with redirection. The getline command is a complex subject which I will cover only relatively briefly. You are directed to the getline section of the GNU Awk User’s Guide for the full details.

Long notes

I have provided detailed notes as usual for this episode, and these can be viewed here.

Links GNU Awk User’s Guide Explicit Input with getline Using getline with No Arguments Using getline with a coprocess Getline notes Two-way I/O Previous shows in this series on HPR: “Gnu Awk - Part 1” - episode 2114 “Gnu Awk - Part 2” - episode 2129 “Gnu Awk - Part 3” - episode 2143 “Gnu Awk - Part 4” - episode 2163 “Gnu Awk - Part 5” - episode 2184 “Gnu Awk - Part 6” - episode 2238 “Gnu Awk - Part 7” - episode 2330 “Gnu Awk - Part 8” - episode 2438 “Gnu Awk - Part 9” - episode 2476 “Gnu Awk - Part 10” - episode 2526 “Gnu Awk - Part 11” - episode 2554 “Gnu Awk - Part 12” - episode 2610 “Gnu Awk - Part 13” - episode 2804 “Gnu Awk - Part 14” - episode 2816 Resources: ePub version of these notes Examples: awk15_testdata1, awk15_ex1.awk, awk15_ex2.awk, awk15_testdata2, awk15_ex3.awk, awk15_ex4.awk, awk15_ex5.awk, awk15_ex6.awk, awk15_ex7.awk

HPR2823: Gentoo and why I use it

May 29, 2019


Thanks to norrist for suggesting I do this episode!


HPR2822: What's in the Box! Part 1

May 28, 2019


NYbill opens a mystery box that arrived in the mail.

No spoilers. But, it involves soldering…

Pics for the episode:


HPR2821: Interviewing some exhibitors at the 2019 vcfe.org event

May 27, 2019


I visited the vcfe.org event in Munich, Germany.

Below you will find some urls for the projects that I came across.

Steckschwein 6502 computer: https://steckschwein.de/ Siemens Simatic S5 PLC: https://en.wikipedia.org/wiki/Simatic_S5_PLC CP/M operating system: https://en.wikipedia.org/wiki/CP/M Old fashioned MUD game Nemesis: http://nemesis.de Eastern Germany Robotron hardware: https://en.wikipedia.org/wiki/VEB_Robotron

If you like these things, the next exhibition will be in September in Berlin (you can find more info on vcfb.de).

Regards, Jeroen Baten

HPR2820: 29 - CERT Home Security Tips

May 24, 2019


The Computer Emergency Readiness Team of the US Department of Homeland Security issues a security bulletin, ST15-002, which has tips for home network security. In this episode we review these tips and why they make sense.

Links: https://www.us-cert.gov/ncas/tips/ST15-002 http://www.zwilnik.com/

HPR2819: Reply to Knightwise - podcasts

May 23, 2019


Knightwise, in HPR 2798, made the argument that podcasts are better if they are done by "pirates", i.e. not by corporations, but by individuals with something to say. While I see some merit in this view, I think the more significant feature of podcasts is that it gets us away from "broadcasting" (shows aimed at the lowest common denominator) and towards "narrowcasting", an environment where small niche interests can find an audience and thrive since podcasting does not require a lot of resources. But I do appreciate the chance to hear some radio programs that I would not otherwise be able to listen to when they are offered as podcasts.

Links: https://www.npr.org/podcasts/583350334/science-friday https://www.bbc.co.uk/programmes/b00snr0w http://www.palain.com

HPR2818: Writing Web Game in Haskell - Science, part 1

May 22, 2019



This is rather large topic, so I split it in two episodes. Next one should follow in two weeks if everything goes as planned. First part is about modeling research, while second part concentrates on how things change over time.

There’s three types of research: engineering, natural sciences and social sciences. Research costs points that are produced by various buildings.


There’s three database tables, which are defined below:

CurrentResearch type Technology progress Int factionId FactionId AvailableResearch type Technology category TopResearchCategory factionId FactionId CompletedResearch type Technology level Int factionId FactionId date Int Data types

Technology is enumeration of all possible technologies. Knowing these enable player to build specific buildings and space ships, enact various laws and so on. In the end this will be (hopefully) large list of technologies.

data Technology = HighSensitivitySensors | SideChannelSensors | HighTensileMaterials | SatelliteTechnology | BawleyHulls | SchoonerHulls | CaravelHulls ... deriving (Show, Read, Eq, Enum, Bounded, Ord)

All research belong to one of the top categories that are shown below:

data TopResearchCategory = Eng | NatSci | SocSci deriving (Show, Read, Eq, Ord)

ResearchCategory is more fine grained division of research. Each of the categories is further divided into sub-categories. Only EngineeringSubField is shown below, but other two are similarly divided.

data ResearchCategory = Engineering EngineeringSubField | NaturalScience NaturalScienceSubField | SocialScience SocialScienceSubField deriving (Show, Read, Eq) data EngineeringSubField = Industry | Materials | Propulsion | FieldManipulation deriving (Show, Read, Eq)

ResearchScore is measure of how big some research is. It has type parameter a that is used to further quantify what kind of ResearchScore we’re talking about.

newtype ResearchScore a = ResearchScore { unResearchScore :: Int } deriving (Show, Read, Eq, Ord, Num)

TotalResearchScore is record of three different types of researches. I’m not sure if I should keep it as a record of three fields or if I should change it so that only one of those values can be present at any given time.

data TotalResearchScore a = TotalResearchScore { totalResearchScoreEngineering :: ResearchScore EngineeringCost , totalResearchScoreNatural :: ResearchScore NaturalScienceCost , totalResearchScoreSocial :: ResearchScore SocialScienceCost } deriving (Show, Read, Eq)

Following singleton values are used with ResearchScore and TotalResearchScore to quantify what kind of value we’re talking about.

data EngineeringCost = EngineeringCost deriving (Show, Read, Eq) data NaturalScienceCost = NaturalScienceCost deriving (Show, Read, Eq) data SocialScienceCost = SocialScienceCost deriving (Show, Read, Eq) data ResearchCost = ResearchCost deriving (Show, Read, Eq) data ResearchProduction = ResearchProduction deriving (Show, Read, Eq) data ResearchLeft = ResearchLeft deriving (Show, Read, Eq)

Finally there’s Research, which is a record that uses many of the types introduced earlier. It describes what Technology is unlocked upon completion, what’s the cost is and if there are any technologies that have to have been researched before this research can start. The tier of research isn’t currently used for anything, but I have vague plans what to do about it in the future.

data Research = Research { researchName :: Text , researchType :: Technology , researchCategory :: ResearchCategory , researchAntecedents :: [Technology] , researchCost :: TotalResearchScore ResearchCost , researchTier :: ResearchTier } deriving (Show, Read, Eq) Tech tree

Putting all this together, we can define a list of Research. Since finding an entry from this list based on research type of it is such a common operation, we also define another data structure for this specific purpose. Map in other programming languages is often known as dictionary, associative array or hash map. It stores key-value - pairs. In our case Technology is used as key and Research as value. We define it based on the list previously defined:

techMap :: Map.Map Technology Research techMap = Map.fromList $ (\x -> (researchType x, x)) <$> unTechTree techTree

Next time we’ll look into how to actually use all these types and data that were defined.

HPR2817: Are you successful? Click to find out more!

May 21, 2019


Based on https://libranet.de/display/0b6b25a8-125c-a71f-c7ae-f1a686792961.

It’s pretty short, less than 4 minutes, but I think it’s important.

Who defines whether you are successful, or whether your project is successful, and does it matter?

HPR2816: Gnu Awk - Part 14

May 20, 2019



This is the fourteenth episode of the “Learning Awk” series which is being produced by b-yeezi and myself.

In this episode and the next I want to start looking at redirection within Awk programs. I had originally intended to cover the subject in one episode, but there is just too much.

So, in the first episode I will be starting with output redirection and then in the next episode will spend some time looking at the getline command used for explicit input, often with redirection.

Long notes

I have provided detailed notes as usual for this episode, and these can be viewed here.

Links GNU Awk User’s Guide Redirecting output of print and printf Special Files for Standard Preopened Data Streams Special File names in gawk Previous shows in this series on HPR: “Gnu Awk - Part 1” - episode 2114 “Gnu Awk - Part 2” - episode 2129 “Gnu Awk - Part 3” - episode 2143 “Gnu Awk - Part 4” - episode 2163 “Gnu Awk - Part 5” - episode 2184 “Gnu Awk - Part 6” - episode 2238 “Gnu Awk - Part 7” - episode 2330 “Gnu Awk - Part 8” - episode 2438 “Gnu Awk - Part 9” - episode 2476 “Gnu Awk - Part 10” - episode 2526 “Gnu Awk - Part 11” - episode 2554 “Gnu Awk - Part 12” - episode 2610 “Gnu Awk - Part 13” - episode 2804 Resources: ePub version of these notes Examples: awk14_fruit_data.txt, awk14_ex1.awk, awk14_ex2.awk, awk14_ex3.awk

HPR2815: Copy pasta

May 17, 2019


You can copy and paste on Linux the same way you do on any other OS: Ctrl+C to copy and Ctrl+V to paste (or use the Edit menu, or a right-click menu).

However, Linux doesn't limit you to just that. The primary GUI environment of Linux (at the time of this recording) is X, and the Inter-Client Communication Conventions Manual defines three X Selection states: Primary, Secondary, and Clipboard. The Secondary is rarely (if ever?) used, so I don't cover it here.


The primary X Selection is anything literally selected at any given moment. If you highlight a word in Firefox with your mouse, for instance, then it becomes the Primary Selection, and it is owned by Firefox. If you press the Middle Mouse Button in any application, then that application asks the owner (Firefox, in this example) for the data contained in the Primary Selection. Firefox sends the data to that application so that it can paste it for you.

A Primary selection remains the Primary Selection until it is overwritten by a new Primary Selection. In other words, text needn't be highlighted to be retained in the Primary Selection slot.


The Clipboard Selection is data that has explicitly been sent to the clipboard by a copy action. This is usually a right-click > Copy or a selection of Edit > Copy. When another application is told to paste from the clipboard, it pastes data from the Clipboard Selection.


You can (and often do) have both a Primary Selection and a Clipboard selection. If you press Ctrl+V, you get the contents of the Clipboard Selection. If you press the middle mouse button, then you get the contents of the Primary Selection.


The xsel command allows you to retrieve the contents of an X Selection.

$ xsel --primary dungeons $ xsel --clipboard dragons Clipboard managers Clipboard managers such as Klipper, CopyQ, Parcellite, and so on, provide a history for your clipboard. They track the latest 10 (or so) items you have copied or selected. They can be a little confusing, because they do tend to blur the line between the Primary Selection and the Clipboard Selection, but now that you know the technical difference, it shouldn't confuse you to see them both listed by a clipboard manager designed to conflate them.


GPM is a daemon allowing you to use your mouse without a GUI. Among its features, it permits you to select text in a text console (TTY) and then paste it with the middle mouse button.

GNU Screen and Tmux

Screen and tmux are "window managers for text consoles". I don't tend to use tmux as often as I should, having learnt GNU Screen long ago, so I'm not familiar with the process of copying and pasting with tmux. For Screen, you can copy text in this way:

Press Ctrl+A to get out of insert mode.

Press left-square_bracket to enter copy-mode

Move your text to the position you want to start selecting and press Enter or Return

Arrow to the position at which you want to end your selection and press Enter or Return again

To paste your selection:

Press Ctrl+A to get out of insert mode.

Press right-square_bracket to paste

HPR2814: Spectre and Meltdown and OpenBSD and our future

May 16, 2019


I discuss the entire Spectre and Meltdown issues and where we might go post an Intel world. My objective is to encourage others to leave Speculative processing backed by management engine based chips. SCATTER HUMANS!!! WE MUST LEAVE!!!!

HPR2813: Should we dump the linux Desktop.

May 15, 2019


Knightwise wonders if we should let go of the linux desktop environments and focus on cross-platform applications instead. Please bring your torches and pitchforks.

HPR2812: Is 5G mobile data a danger to your health?

May 14, 2019


This is mostly verbatim from my Fediverse post https://libranet.de/display/0b6b25a8-165c-9c7f-b55d-c7a077813050, with a few minor edits.

The anti-5G campaign has been cooking for many years now, and at the epicenter of it all are two men, Lennart Hardell and Rainer Nyberg. It’s a Swedish-Finnish phenomenon that is now really making the rounds and spreading internationally, as actual commercial deployment of 5G networks draws nearer.

As a Swede, I apologize. These two do not represent the Swedish or Finnish cancer or radiation research community, and our media have given them far more space in the public discourse than their work merits.

They are heavily quoted in networks of pseudoscience, including anti-vaccine sites, right-wing "alternative facts" sites and Strålskyddsstiftelsen ("Swedish Radiation Protection Foundation"), a private foundation created in 2012 with a deceptive name meant to invoke authority, which has had to be corrected on multiple occasions by the actual Swedish Radiation Safety Authority, Strålskyddsmyndigheten.

Strålskyddsstiftelsen received the 2013 "Misleader of the Year" award from the main Swedish scientific skeptics' society, Vetenskap och Folkbildning ("Science and Public Education") for "[their fearmongering propaganda and biased reporting on the health effects of mobile telephony use and wireless networks]".

https://www.vof.se/utmarkelser/tidigare-utmarkelser/aretas-forvillare-2013/ (in Swedish)

These networks are part of a feedback loop where they get media attention, politicians pick up on their claims and use them to invoke the precautionary principle and get precautionary regulation in place, or judges rule based on the claims, which then gets quoted by these entities as evidence that they were right all along.

They make it very hard to find factual information on whether millimeter-wavelength radiation actually has any different effect from the centimeter-wavelength radiation that we have been using for over two decades without any documented harmful effects, because wherever you look you just find these sites claiming that we have definitely had adverse health effects for the last two decades and the new frequency bands will definitely be far worse.

When you dig deeper into the claims on these sites you find a handful of cherry-picked articles, leading back to the two men mentioned at the top, to studies with flawed methodology like self-reported surveys on mobile telephony use among cancer patients, or to the pseudoscience/media/politics/law feedback loop. And it’s all about centimeter waves, which simply have shown no conclusive sign of increasing brain cancers or any other adverse health effect related to the radiation. For every positive report made you can find one that reports brain cancer fell as we introduced mobile phones. There is a massive body of data, and if the signal were there, we would have seen it by now.

I’m no cancer researcher, but neither is Rainer Nyberg, he’s a retired professor in pedagogy. He’s a concerned citizen. https://en.wikipedia.org/wiki/Lennart_Hardell is an actual oncologist and professor who has studied carcinogens, but his research results on the wireless/cancer connection have been dismissed as "non-informative", "post hoc", "barely statistically significant" and "flawed" by his peers. There is nothing there.

We know that high-voltage 16.7 Hz fields increase the risk for leukemia in train drivers, but we don’t know why. I am open to the possibility that 20-50 GHz waves have different consequences from 2 GHz waves, but I’d have to hear it from a credible source.

Straight up DNA mutation is out the window, and that’s one of the centerpoints of these campaigns. This is still frequencies below visual light, it’s not ionizing radiation. No plausible mechanism has been suggested, and there is no clear data on any adverse effects.

We use millimeter waves for the full body scans in US airports. Surely the effects of those have been studied? The top search results go to truthaboutcancer and infowars and similar names I won’t even bother to click. I don’t want to read another article about how all cancer research after 1950 has been wrong, we should all just eat chalk to balance our acidity, and cancer is a fungus.

Apart from the pseudoscience sites I found one paper on the first search results page, concluding that X-ray backscatter scanners have well-known risks, but radiation levels are far below safety standards, both for passengers and for security staff, and also below the background radiation exposure while flying, and millimeter-wave scanners, while an "alarmingly small amount of information about its potential health effects" is available, "The established health effects associated with non-ionizing radiation are limited to thermal effects" and "these scanners operate at outputs well below those required to produce tissue heating", that is, we currently don’t know of a way millimeter waves might be harmful: https://www.sciencedirect.com/science/article/pii/S1687850714000168 (https://doi.org/10.1016/j.jrras.2014.02.005)

For a guide on how to spot pseudoscience and how to read scientific papers, see ahuka’s excellent hpr2695: Problems with Studies.


HPR2811: Interview with Alan Pope

May 13, 2019


A few years ago, when you wanted to install a package on your Linux system, you had to grab the source code, and the nightmare began. But nowadays, this is over. You have deb files, and snaps, and flatpacks, and many other package formats available. On this episode, I was joined by Alan Pope, from Canonical, to talk about one of them in particular : snaps.

HPR2810: Wi-Fi on Android

May 10, 2019



You're running a firewall on your work and home networks right, so of course you're running one on your Smart Phone. Given this device holds more information about you than you probably know yourself, it would be only prudent to make sure that you are protecting what gets in but also what gets out.

I run AFWall+ which is available from the F-Droid app store. It runs fine on LineageOS.

I then set it on the children's phone so that no application is allowed to use mobile data, and then only applications that need Internet get Internet Access. This works well as it's a normal use case for mobile applications to have intermittent access to the Internet.

I see no reason why the Linux Kernel should need unfettered access to the Internet, so it's not allowed out. One issue you may come across is that even though you know that there is a Connection your phone doesn't, and so it will display the Wi-Fi Connected, no Internet message.

I'm not sure how this check is done but abqnm suggests at in the StackExchange question How does Android determine if it has an Internet connection? that it may be related to Google Cloud Messaging.

... this means that the device is unable to receive a response from GCM (Google Cloud Messaging, the framework that handles push notifications). This traffic is sent through ports 5228, 5229, and 5230. If the AP is blocking or interfering with traffic on those ports, push notifications won't work ...

I do indeed see blocked attempts by Google Play Services on my own phone, but not on the other phones that have no google services installed. The only entry I see in the logs is an ICMP attempt to "Comcast Cable Communications, Inc". If you know more please record a show for Hacker Public Radio about it.

Giving Access

Normally you will get a message saying that the Wi-Fi has no Internet access.

Android System. Wi-Fi has no Internet access. Tap for options

If you tap the message a popup will allow you to stay connected and will let you remember the choice.

OpenWireless.Org. This network has no Internet access. Stay connected? [] Don't ask again for this network NO YES

In some cases the router helpfully resets the connection before you can reply to the message meaning it goes into a loop continually popping up the message but not reacting to it.

In this case we can use Termux a Android Terminal emulator, to drop to a shell and fix the problem.

I used su to get root access but you could also change to the user wifi.

The file you need to edit is /data/misc/wifi/wpa_supplicant.conf. It's probably best to edit this file with the wifi off.

network={ ssid="OpenWireless.Org" key_mgmt=NONE priority=15 id_str="{snip}" }

Scroll down to the network that is giving you trouble and add disabled=1

network={ ssid="OpenWireless.Org" key_mgmt=NONE priority=15 disabled=1 id_str="{snip}" }

I ended up copying the file to the sdcard, and editing it there. I then copied it back as su and used chown wifi:wifi /data/misc/wifi/wpa_supplicant.conf to fix the permissions.

Once that's done you can reboot the phone and connect to the network without a problem. You should also consider putting up an Open Wireless access point yourself.

HPR2809: The Blue Oak Model License and Its One Big Gotcha

May 9, 2019


The Blue Oak Model License 1.0.0 was just released this month. In this episode I read the license, explain where it sits in among other software licenses, and enumerate some of the problems it purports to solve.

I’m no legal expert, so take all of this as sort of a rough introduction to the license.

Overall, if you are looking at permissive (vs copyleft) licenses, I would strongly suggest you consider this license! It’s concise, robust, it was developed by credible people, and gives your users future-proof safety from a number of common legal traps.

However: just note that it has a feature, some would say bug, that might be a big deciding factor in whether you feel comfortable with it (listen for details)

Nevertheless, I believe this license, or at least its style of language, will soon become extremely common.

Further links:

The Blue Oak Model License 1.0.0 — the license itself. You may also wish to read the group’s statement about their methodology and how the license came to be. Deprecation Notice: MIT and BSD — the blog post I mention in the recording, by Blue Oak council member, developer and IP lawyer Kyle Mitchell. He explains some problems he sees with the MIT and BSD licenses and how the BOML addresses them. Discussion on Hacker News — This was a pretty good discussion. Kyle Mitchell also chimed in here to respond to some criticisms and tire-kicking of this license (you can recognize him by his handle kemitchell).

Not mentioned in the recording: One thing that caused me a bit of confusion at first was the term “attribution”. Kyle and the Blue Oak folks use this term mainly to talk about license terms, not authorship or credit. So for them an attribution requirement is a requirement to include the license terms with any distributed copies, not a requirement to give authorship credit to people.

If you want to use this license as a starting point for your own “bespoke” license, you can! As I mention in the recording, I created my own variant of the Blue Oak license for one of my own projects. My main change was a strong requirement for downstream users to give credit to upstream contributors—not just when redistributing source code, but in all published software, books and websites created with the software!

The Local Yarn License 1.0.0 — This is the license as it currently sits in an experimental branch in my project’s Fossil repository Notes about my customizations — Another tech note from the Fossil repo.

Of course, when you make your own changes, you had better think hard about them, and if possible, get the advice of an Actual Lawyer who can discuss your particular situation.

HPR2808: Haskell function types

May 8, 2019


Haskell is statically typed language, meaning that during compilation, programs are checked for type correctness. This means that you won’t accidentally mix for example text and numbers. Haskell does type inference. The compiler will try and figure out what kind of types would make your program to be valid in terms of types. Programmer could completely omit types, but it’s often helpful to write type signatures for at least top level definitions. These will be helpful for both the programmers and compilers.

concrete types

Simplest case is where types are spelled out definitely. Function add below takes two Integer parameters and produces Integer value. Note that types are written in upper case.

add :: Integer -> Integer -> Integer

It’s possible to not use concrete types. In following example a (note the lower case) can be anything. So function takes two values of a, a Boolea and produces a. This is useful technique for writing very general functions.

choose :: a -> a -> Boolean -> a

ad hoc polymorphism

In previous example, we wouldn’t be able to do much at all with a as we don’t know its type. Sometimes we need to know a bit more about type, without specifically declaring its type. For those cases type constraints are useful.

add :: (Num a) => a -> a -> a

This version of add again takes two parameters, both being type a and produces value a. But (Num a) => part in the signature constraints a to be instance of Num. This type class (I’ll talk about these some other time) defines that each instance of it will have set of functions: +, -, *, negate, abs, signum and fromInteger. So now our add function can use those functions, regardless of what specific type a is.

parametrized functions

Types used in function signature can be parametrized. If we wanted a function that returns a first element of any list, we could have following signature: first :: [a] -> Maybe a

first takes single parameter, list of a and returns Maybe a. Maybe is a type that is used to signify a value that might or might not be present and has following definition:

data Maybe a = Nothing | Just a

So our function would return Nothing when given an empty list and Just a when given a list of at least one element.

using functions

Function application in Haskell doesn’t require parentheses around arguments. Calling our add function is just add 1 2. If one of the values is result of another function call, we need to tell which parameters belong to which function. Using $ is one option: add 1 $ add 2 3, another option is to use parentheses: add 1 (add 2 3).

When function is called with less parameters than it expect, instead of run time error you’ll going to receive a function. In following example addLots 5 will produce same value as add 1000 5:

addLots = add 1000 addLots 5

Another contrived example of partial application:

findPodcasts :: [Podcast] -> Text -> [Podcast] search = findPodcasts loadedPodcasts myPodcasts = search "tuturto" functions as types

Functions have type (that’s what the signature is for after all) and functions can be used as values. You can return function from another function or you can pass in a function as a parameter.

Common example is filter, which has following signature: filter :: (a -> Bool) -> [a] -> [a]

It takes two parameters, first one is function that has type a -> Bool and second one is list of a. Return value is list of a. You can produce a list of odd numbers between 1 and 10 with filter odd [1..10].

anonymous functions

Sometimes you need a function to pass in as a parameter, but the function is so small that you don’t want to give it a name. For those cases, anonymous function are good. If you wanted to produce a list of odd numbers that are greater that 5 in range from 1 10, you could write it as: filter (\x -> odd x && x > 5) [1..10]. If you squint hard enough \ looks almost like a lowercase greek letter λ.

Easiest way to catch me is either email or fediverse where I’m tuturto@mastodon.social

HPR2807: Are bash local variables local?

May 7, 2019



In hpr2739, Dave talked briefly about local variables. But what are they?

In most modern languages, especially in compiled languages, "local" means that the value of a variable cannot be directly known, by looking up the name, outside the bounds of that function, but that’s not how it works in bash.

Languages like C and Python have lexical scope. Lexical scope means local variables are local in the text. The names are local.

If I’m writing code that is textually located outside the function, I cannot even describe how to access the variables within the function, because myvariable in my function is not the same variable, not the same place, as myvariable in your function.

Languages like Bash and Elisp have dynamic scope. That means local variables are local in time. The names are global.

What happens when you declare a variable local in bash is that the existing value of that variable is stowed away, to be brought back when your function exits.

#!/usr/bin/env bash function sayscope() { echo The scope is $whatsmyscope } function globalscope() { whatsmyscope=global } function dynamicscope() { whatsmyscope=dynamic } function localscope() { local whatsmyscope=local sayscope dynamicscope sayscope } globalscope sayscope localscope sayscope The scope is global The scope is local The scope is dynamic The scope is global

Perl has both, and it calls them local (dynamic scope, like bash) and my (lexical scope):

#!/usr/bin/env perl use v5.10; sub sayscope { say "Dynamic scope is $whatsmyscope"; } sub globalscope { $whatsmyscope="global"; } sub dynamicscope { $whatsmyscope="dynamic"; } sub lexicalscope { my $whatsmyscope="lexical"; say "Lexical scope is $whatsmyscope"; sayscope; } sub localscope { local $whatsmyscope="local"; sayscope; dynamicscope; sayscope; lexicalscope; } globalscope; sayscope; localscope; sayscope; Dynamic scope is global Dynamic scope is local Dynamic scope is dynamic Lexical scope is lexical Dynamic scope is dynamic Dynamic scope is global

You almost never want to use local in Perl, it’s mostly there for historical reasons — lexical scope is a Perl 5 feature. https://perl.plover.com/local.html covers well the remaining few and narrow exceptions where local might be useful.

As dynamic scope has some valid use, it’s available in some otherwise lexically scoped languages. For example, Common LISP has the special form, and several Schemes and Racket have parameter objects:




To dig fully into the history and flora of dynamic and lexical scope merits another episode.

HPR2806: HPR Community News for April 2019

May 6, 2019


New hosts

There were no new hosts this month.

Last Month's Shows Id Day Date Title Host 2781 Mon 2019-04-01 HPR Community News for March 2019 HPR Volunteers 2782 Tue 2019-04-02 Never stop gaming klaatu 2783 Wed 2019-04-03 The Windows "Shutdown.exe" Command Explained Claudio Miranda 2784 Thu 2019-04-04 The Yamaha Disklavier Jon Kulp 2785 Fri 2019-04-05 What is uCPE JWP 2786 Mon 2019-04-08 My YouTube Channels Tony Hughes AKA TonyH1212 2787 Tue 2019-04-09 NodeJS Part 1 operat0r 2788 Wed 2019-04-10 Looping in Haskell tuturto 2789 Thu 2019-04-11 Pacing In Storytelling lostnbronx 2790 Fri 2019-04-12 My YouTube Subscriptions #5 Ahuka 2791 Mon 2019-04-15 LUKS like truecrypt klaatu 2792 Tue 2019-04-16 Playing around with text to speech synthesis on Linux Jeroen Baten 2793 Wed 2019-04-17 bash coproc: the future (2009) is here clacke 2794 Thu 2019-04-18 Interview with Martin Wimpress Yannick the french guy from Switzerland 2795 Fri 2019-04-19 Dead Earth klaatu 2796 Mon 2019-04-22 IRS,Credit Freezes and Junk Mail Ohh My! operat0r 2797 Tue 2019-04-23 Writing Web Game in Haskell - Simulation at high level tuturto 2798 Wed 2019-04-24 Should Podcasters be Pirates ? knightwise 2799 Thu 2019-04-25 building an arduino programmer Brian in Ohio 2800 Fri 2019-04-26 My YouTube Subscriptions #6 Ahuka 2801 Mon 2019-04-29 Guitar Set Up Part 1. NYbill 2802 Tue 2019-04-30 Mid-life (?) assessment clacke Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows. There are 23 comments in total.

Past shows

There are 4 comments on 4 previous shows:

hpr2457 (2018-01-02) "Getting ready for my new Macbook Pro" by knightwise. Comment 1: Bart on 2019-04-25: "aren't you forgetting a hub?"
hpr2739 (2019-01-31) "Bash Tips - 19" by Dave Morriss. Comment 1: clacke on 2019-04-01: "local"
hpr2774 (2019-03-21) "CJDNS and Yggdrasil" by aldenp. Comment 5: clacke on 2019-04-01: "Yggdrasil pronunciation"
hpr2779 (2019-03-28) "HTTP, IPFS, and torrents" by aldenp. Comment 2: clacke on 2019-04-01: "audio quality"
This month's shows

There are 19 comments on 7 of this month's shows:

hpr2783 (2019-04-03) "The Windows "Shutdown.exe" Command Explained" by Claudio Miranda. Comment 1: Bubba on 2019-04-04: "Shutdown.exe command"Comment 2: ClaudioM on 2019-04-06: "Also Useful with PsExec from Sysinternals Suite"
hpr2784 (2019-04-04) "The Yamaha Disklavier" by Jon Kulp. Comment 1: tuturto on 2019-04-04: "music to ears"Comment 2: Jan on 2019-04-04: "Translations"Comment 3: Jon Kulp on 2019-04-04: "Ok but it wasn't the "Well-Tempered Piano""Comment 4: Gavtres on 2019-04-05: "So cool!"Comment 5: Dave Morriss on 2019-04-05: "What a wonderful device!"Comment 6: Guy on 2019-04-06: "How far away are you?"Comment 7: Jon Kulp on 2019-04-06: ""or" not "of""Comment 8: Windigo on 2019-04-14: "Library of Congress"Comment 9: Jon Kulp on 2019-04-15: "A great summer job"Comment 10: Jon Kulp on 2019-04-18: "Older near-perfect player pianos"
hpr2787 (2019-04-09) "NodeJS Part 1" by operat0r. Comment 1: tuturto on 2019-04-10: "looking for more"
hpr2789 (2019-04-11) "Pacing In Storytelling" by lostnbronx. Comment 1: tuturto on 2019-04-11: "what about non-fictional stories"
hpr2793 (2019-04-17) "bash coproc: the future (2009) is here" by clacke. Comment 1: Dave Morriss on 2019-04-22: "I really enjoyed this!"
hpr2796 (2019-04-22) "IRS,Credit Freezes and Junk Mail Ohh My!" by operat0r. Comment 1: cogoman on 2019-04-25: "Credit card security"
hpr2798 (2019-04-24) "Should Podcasters be Pirates ?" by knightwise. Comment 1: tuturto on 2019-04-24: "Yarrr, record me episodes"Comment 2: Dave Morriss on 2019-04-27: "Memories of early podcasts and pirate radio"Comment 3: DudeNamedBen on 2019-04-29: "Da Podfather, Adam Curry"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-April/thread.html Events Calendar

With the kind permission of LWN.net we are linking to The LWN.net Community Calendar.

Quoting the site:

This is the LWN.net community event calendar, where we track events of interest to people using and developing Linux and free software. Clicking on individual events will take you to the appropriate web page. Any other business HPR on Wikipedia

Please see the draft at https://en.wikipedia.org/w/index.php?title=Draft:Hacker_Public_Radio

If you are not already a host, then please help improve the site.

Tags and Summaries

Thanks to the following contributor for sending in updates in the past month: Tony Hughes

Over the period tags and/or summaries have been added to 36 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2805: My 50th Show

May 3, 2019


Hallo this is again Tony Hughes for HPR. This is an auspicious show for me as it’s my 50th show that I have recorded and released on HPR in my own right. However prior to my 1st show in my own right I did guest on 2 shows.

The first of these was:

hpr0844 :: The Flying Handbag hosted by HPR Volunteers
Released: 2011-10-26

Which was a show that was recorded at Barcamp Blackpool in 2011, when a group of us got together to record a podcast, the hilarious thing was that the only place we could find to record was a stairwell which happened to be next to the toilets, definitely not family friendly but if you want a laugh have a listen.

The next show I appeared on was an interview I did with Ken Fallon at my first OggCamp in the same year.

hpr0863 :: Tony Hughes Free Cycle hosted by Ken Fallon
Released: 2011-11-22.

Ken was as usual trying to recruit new hosts and interviewed me with the hope that I would become one. Well I did but it took another 5 years before I finally recorded my first show in my own right.

First just to say the idea for this show comes from hpr2700 in which Ken created a script to automate the bot voice reading a list of every show that has been released on HPR, so to celebrate my 50th Show I thought I would list my shows but with me running through them and do a brief summary of the show where appropriate.

hpr2051 :: My Linux Journey
Released on 2016-06-13
in this episode I talked about my journey in computing and starting to use Linux

hpr2056 :: Interview with a young hacker
Released on 2016-06-20
This was my first of several interviews with @All_about_Code at my local Raspberry Jam

hpr2065 :: Whats in My Bag
Released on 2016-07-01
Looking at this show so tells me I have to redo this show as my bag is very different these days

hpr2076 :: What Magazines I read Part 1
Released on 2016-07-18
just what the title said, I talked about the magazines I was reading at that point in time.

hpr2087 :: Magazines I read Part 2
Released on 2016-08-02
This was a follow up of the last show

hpr2097 :: New Toys
Released on 2016-08-16
I talked about my hardware journey over the last 30 odd years and talked about the i7 system I had just bought 2nd hand

hpr2101 :: What’s on my podcatcher
Released on 2016-08-22
A show about the podcasts I listen to.

hpr2144 :: An Interview with All About Code at Manchester BarCamp
Released on 2016-10-20
a follow up interview with Josh

hpr2151 :: BarCamp Manchester part 2
Released on 2016-10-31
An interview with Claire, the organiser of BarCamp Manchester.

hpr2157 :: BarCamp Manchester part 3
Released on 2016-11-08
This was an interview with Alan O’Donohoe who had started the Raspberry Jam movement

hpr2257 :: Watt OS
Released on 2017-03-28
Acer Aspire One Netbook – Review

hpr2265 :: WattOS on Lenovo X61s
Released on 2017
Lenovo X61s – Review

hpr2271 :: Raspberry Pi Zero W
Released on 2017-04-17
Review Episode on the then New Pi Zero W

hpr2280 :: Lenovo X61s Part 2
Released on 2017-04-28
Follow up review after a SSD upgrade and using Linux Lite

hpr2286 :: Surviving a Stroke
Released on 2017-05-08
A very personal episode about my surviving a Stroke in February 2017

hpr2295 :: MX Linux
Released on 2017-05-19
A review episode using this OS on a Lenovo X230i after a hardware boot issue with Linux Mint and an SSD

hpr2331 :: Liverpool Makefest 2017 Show 1
Released on 2017-07-10
The first of a number of interview shows from the 2017 Liverpool Makefest

hpr2336 :: Liverpool Makefest 2017 Show 2
Released on 2017-07-17

hpr2341 :: Liverpool Makefest 2017 Show 3
Released on 2017-07-24

hpr2346 :: Liverpool Makefest 2017 Show 4
Released on 2017-07-31

hpr2352 :: Liverpool Makefest 2017 Show 5
Released on 2017-08-08

hpr2362 :: Raspbian X86 on Lenovo x61s
Released on 2017-08-22
Review of Raspbian X86 on a Lenovo X61s

hpr2366 :: Making Bramble Jelly
Released on 2017-08-28
Just what it says on the tin I talk about making Bramble jelly,

hpr2374 :: How to Make Sauerkraut
Released on 2017-09-07
Another food show on how to make Sauerkraut

hpr2380 :: Raspbian X86 on P4 Tower
Released on 2017-09-15
Follow up this time running Raspbian X86 on an old P4 Tower

hpr2405 :: Nokia 6 Review
Released on 2017-10-20
I reviewed my new phone

hpr2432 :: Living with the Nokia 6 – an update to HPR 2405
Released on 2017-11-28
Follow up update show having lived with the phone for a couple of months.

hpr2442 :: The sound of Woodbrooke Quaker Study centre in the Spring
Released on 2017-12-12
This was a soundscape recording I made at Woodbrooke Quaker Study Centre in Birmingham UK while I was there in April 2017.

hpr2579 :: Ubuntu 18.04 Mate
Released on 2018-06-21
A review of the recently released Ubuntu 18.04 Mate

hpr2590 :: Blowing a PC Power Supply
Released on 2018-07-06
A show about how not to blow your PC power supply

hpr2595 :: New laptop bargain?
Released on 2018-07-13
A review on my recently purchased secondhand Toshiba Z30 laptop

hpr2601 :: Liverpool Makerfest 2018
Released on 2018-07-23
Chris Dell

hpr2606 :: Liverpool Makefest 2018 - interview with Dan Lynch
Released on 2018-07-30
A podcast Legend

hpr2612 :: Liverpool Makefest 2018 - interview with Joe aka Concrete Dog
Released on 2018-08-07
About Rocketry

hpr2616 :: Liverpool Makefest 2018 - interview with Josh - A.K.A - All About Code
Released on 2018-08-13.
This is another short interview recorded at Liverpool Makefest, with Josh talking about EduBlocks.

hpr2621 :: Liverpool Makefest 2018 - Chan’nel Thomas a.k.a little pink maker
Released on 2018-08-20
I talk to Chan’nel Thomas aka little pink maker.

hpr2626 :: Liverpool Makefest 2018 - interviews with Helen and Chris
Released on 2018-08-27
In this episode I talk to Helen from Manchester Hackspace and Chris from Wirral Code Club

hpr2632 :: Liverpool Makefest 2018 - interviews with Robert and Carl
Released on 2018-09-04
In this episode I talk to Robert from Roberts Workshop and Carl from Edgehill University

hpr2636 :: Liverpool Makefest 2018 - interviews with Noel from JMU FabLab
Released on 2018-09-10

hpr2641 :: Liverpool Makefest 2018 - interview with Rachel from the MicroBit Foundation
Released on 2018-09-17

hpr2646 :: Liverpool Makefest 2018 - Interview with Steve and Gerrard from the Liverpool Astronomical society.
Released on 2018-09-24

hpr2652 :: Liverpool Makefest 2018 - Interview with Caroline and John
Released on 2018-10-02 under a CC-BY-SA license.
This was the final interview from Makefest 2018 in Liverpool. In this interview I interview one of the founder members of Makefest, Caroline Keep, and the Head Teacher of the school where she works, John Carling.

hpr2663 :: Short review on a 2.5 inch SSD/HDD caddy
Released on 2018-10-17
Quick hardware review

hpr2702 :: Audacity set up and response to episode 2658
Released on 2018-12-11
I post my response to show 2658 by Dave and Al

hpr2735 :: Soffritto
Released on 2019-01-25
Another food show

hpr2738 :: My Applications
Released on 2019-01-30
This and my 47th episode were about the applications I use in Linux

hpr2746 :: My software part 2
Released on 2019-02-11

hpr2772 :: My applications and software part 3
A short show about the software I use in Linux Mint

hpr2786 :: My YouTube Channels
A short show about some of my YouTube channels inspired by Ahuka


HPR2804: Awk Part 13: Fix-Width Field Processing

May 2, 2019


Basic usage

Use the FIELDWIDTHS = "n1 n2 n3 ..." annotation in the BEGIN section of an awk command to specify the widths of the fields.

For instance, the following file has widths of 20, 10, and 12 characters.

NAME STATE TELEPHONE John Smith WA 418-311-4111 Mary Hartford CA 319-219-4341 Evan Nolan IL 219-532-5301 Boris Ratinski NC 201-553-5555

Below is an example of processing such a file:

BEGIN { FIELDWIDTHS = "20 10 12" } NR > 1 { name = $1 state = $2 phone = $3 sub(/ +$/, "", name) sub(/ +$/, "", state) sub(/ +$/, "", phone) printf("%s lives in %s. The phone number is %s.\n", name, state, phone) }

Then you can run the command:

awk -f process_fixed_width.awk fixed_width.txt

HPR2803: Update on my Raspi 3 B OpenMedia Vault and Next Cloud instances

May 1, 2019


This link was the first product and it is not available any more.

This link tells you about all the different ways to do next cloud.

The link above is what worked exactly for me.

The link above is about what OMV is.

Is were I got my image.

I use a Toshiba 4TB non-powered drive external usb 3 drive.

HPR2802: Mid-life (?) assessment

Apr 30, 2019


At 40, I’m at the middle of the mean life expectancy in most parts of the world. What’s happened so far, and where do I go from here?

I look at my life’s past in increasingly smaller chunks of years, and then at my life’s future in increasingly larger chunks of years, and speculate about those 80 years — or perhaps many more? — of expected lifetime.

I’m saying mostly the things I wrote at https://loadaverage.org/conversation/10689347 but with some small updates from the last 9 months.

HPR2801: Guitar Set Up Part 1.

Apr 29, 2019


NYbill talks about setting up a guitar.

Pics for the episode:


HPR2800: My YouTube Subscriptions #6

Apr 26, 2019


I am subscribed to a number of YouTube channels, and I am sharing them with you

SgtPepper Channel - https://www.youtube.com/channel/UCAZZwDyOoSG32tIpMjQ-EKA Sid Meier’s Civilization - https://www.youtube.com/channel/UCWj7XnnfbKHGVnZ8iSoETSQ Sixty Symbols - https://www.youtube.com/channel/UCvBqzzvUBLCs8Y7Axb-jZew Smarter Every Day - https://www.youtube.com/channel/UC6107grRI4m0o2-emgoDnAA Space Frontier Foundation - https://www.youtube.com/channel/UCe_aC8RselByR6B2UMnprQA Streamin’ Freedom - https://www.youtube.com/channel/UCEl_3AAj2pA-GvkxTS7-mxg Suibhne - https://www.youtube.com/channel/UCQD-0MjUbDBwm2UTVYr0Dag Talk More Talk - https://www.youtube.com/channel/UC7rNO8_kPBH-caQH9vzNe8A The Beatles - https://www.youtube.com/channel/UCc4K7bAqpdBP8jh1j9XZAww The Economist - https://www.youtube.com/channel/UC0p5jTq6Xx_DosDFxVXnWaQ The Extraordinary Universe - https://www.youtube.com/channel/UC_2MM6tCMKWCj-AnvjIhJtw The Great War - https://www.youtube.com/channel/UCUcyEsEjhPEDf69RRVhRh4A The Planetary Society - https://www.youtube.com/channel/UCi0TZmFfgS4oQPcRQ6-KRXg The Saxy Gamer - https://www.youtube.com/channel/UCJCY4j5zSuV1TFN2VQGeD0Q Totally Trailer - https://www.youtube.com/channel/UCuMYtpUa2kaPaG4tBlJAZOA Trailer Life DIY - https://www.youtube.com/channel/UCMmzjxJREn4kDK-ypq9oA7w Veritasium - https://www.youtube.com/channel/UCHnyfMqiRRG1u-2MsSQLbXA Vintage space - https://www.youtube.com/channel/UCw95T_TgbGHhTml4xZ9yIqg Vlogbrothers - https://www.youtube.com/channel/UCGaVdbSav8xWuFWTadK6loA https://www.palain.com/

HPR2799: building an arduino programmer

Apr 25, 2019



1.1 brian in ohio

1.2 out from under my rock


2.1 ken fallon bootloader episode

hpr 2660 burned many bootloaders used usbtiny programmer putting together a programmer would be a good learning experience

2.2 still use arduino

easy to check out a new piece of hardware boards are cheap and easy to find boards are robust

2.3 need to run an arduino board at lower frequency

developing a data logger write code in c using the avr open source tool chain prototype on arduino board needed supplies

3.1 arduino ide

get from your distro’s repository slackbuilds i used the version that repackages the binaries, the little a arduino read this good information

3.2 avrdude

use it to test the programmer outside of the arduino environment part of the gnu avr toolchain

3.3 arduino nano clone - un assembled


look for the boards that have the unpoplated icsp header make sure its a nano and not a pro-mini

3.4 3 leds 3mm or smaller


optional but are useful, especially the heartbeat led

3.5 3 resistors 200 ohm - small

if you install the led’s

3.6 1 5-10 uF electrolytic capacitor

3.7 3-4 inch long jumper wire

3.8 2x3 female header


3.9 some way to cut wire

3.10 soldering supplies


4.1 upload arduino isp sketch to nano


i modified the sketch changing where the led’s are placed

i put the led’s at digital 9, 7, and 5 for spacing

#define RESET 10 // Use pin 10 to reset the target rather than SS #define LED_HB 9 // No change define LED_ERR 7 // changed define #LED_PMODE 5 // changed

upload the sketch

4.2 solder on led’s


solder the anode leg to the apropriate digital pin on the board add a resistor to the cathode leg of the led (usually the shorter leg) solder the resistor attached to the cathode to ground pin of the board i started with pin 9 you can test each led before moving on to the next led my soldering ended up messy but it gets the job done


4.3 modify sketch and test leds

you can modify the sketch change the heartbeat pin to whatever led you just soldered upload the modified sketch the led you just soldered should pulse

4.4 clip jumper wire and attach


pin 10 used the hole on the end of the board as strain relief

4.5 add capacitor

watch polarity no more auto reset if you want to program with arduino ide, you need to push the reset button

4.6 2x3 header

MISO -|o o|-+Vcc SCK -|o o|-MOSI Do not attach-Reset-|o o|-Gnd -----


remove reset connecter south-west connector solder the remaining 5 pins the header is soldered on the bottom of the board


how to use

5.1 plug usb cable into programmer and your computer

5.2 start the arduino ide

5.3 plug programmer onto target board remember to plug the wire into the reset pin of the target

5.4 in the tools folder of the ide make sure your usb port is selected


5.5 and that in the programmer section you select arduino as isp not arduinoisp

Tools→Programmer→Arduino as ISP

5.6 at this point you can burn a bootloader as Ken described

5.7 upload a program

5.7.1 bring up the blink example sketch

5.7.2 under tools make sure your target board type is selected


5.7.3 under the sketch menu you’ll see upload using a programmer

Sketch→Upload Using Programer

5.7.4 when you select that the blink sketch will be compiled and uploaded

at the command line

6.1 check functionallity

bash-4.3$ avrdude -p m328p -c arduino -P /dev/ttyUSB0 -b 19200

6.2 output

avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.01s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: safemode: Fuses OK (E:FD, H:DE, L:FF) avrdude done. Thank you. things to look out for

7.1 permissions issues - arch wiki gentoo

7.2 when you upload this way you overwrite bootloader

7.3 arduino ide boards.txt has some fuse errors

7.4 avrdude version 6.2 will not work

7.5 baud rate using avrdude command line

7.6 capacitor is non-optional, but makes uploading to that board non-trivial


8.1 upload via icsp vs usb serial

8.2 do you need a bootloader?

8.3 challenge to max out any 8bit microcontroller

if you need to do one or two things use a microcontroller i.e. arduino if you need to do many things use a linux single board computer i.e. raspberry pi

HPR2798: Should Podcasters be Pirates ?

Apr 24, 2019


In a car rant I think back to the early days of podcasting and how the ambience and vision of podcasting was far from the mainstream media approach from today. Have we all sold out ?

HPR2797: Writing Web Game in Haskell - Simulation at high level

Apr 23, 2019


So far we have been concentrating on separate pieces of the game. Now it’s time to put some of them together as a simulation.

Overview of simulation

Simulation is done in discrete steps. Each step is roughly 1 earth month (completely arbitrary decision). Shorter than that and there might not be enough happening during turns to keep things interesting. Much longer than that and player might not have enough control on how to react things.

In any case, current time is stored in database in table time. There should be only one row in that table at any given time. And that row has only one value, current time. Time is stored as integer as I didn’t want to deal with problems that you get when adding fractions to a float time after time. So current time (March 2019) would be 2019.3 in game terms and stored as 20193 in database.

Main processing is done in function called processTurn that is shown below. It advances time for one decimal month, removes all expired statuses as explained in episode 2768 and then loads all factions.

After that, various steps of the simulation are carried out for all loaded factions. These include handling special events as explained in episode 2748 and doing observations and report writing in manner described episode 2703.

processTurn :: (BaseBackend backend ~ SqlBackend, BackendCompatible SqlBackend backend, PersistUniqueRead backend, PersistQueryWrite backend, PersistQueryRead backend, PersistStoreWrite backend, MonadIO m) => ReaderT backend m Time processTurn = do newTime <- advanceTime _ <- removeExpiredStatuses newTime factions <- selectList [] [ Asc FactionId ] _ <- mapM (handleFactionEvents newTime) factions mapM_ handleFactionFood factions mapM_ (handleFactionConstruction newTime) factions _ <- mapM (addSpecialEvents newTime) factions -- Doing observations should always be done last to ensure players have -- recent reports of property they have full control, ie. planets. -- Otherwise it's possible that they'll receive reports that are one -- turn out of sync. mapM_ (handleFactionObservations newTime) factions return newTime More mapping

Remember map and fmap that are used to run a function to each element in a list or general structure? mapM works in a similar way, but is used in monadic context. In processTurn function, we’re dealing with input and output and have IO monad present to allow us to do that (MonadIO m part of the type signature).

If you step back a bit and squint a bit, then map :: (a -> b) -> [a] -> [b] and fmap :: (a -> b) -> f a -> f b and mapM :: Monad m => (a -> m b) -> t a -> m (t b) look pretty similar. Each take a function, structure and produce a new structure which values were created by running the given function for each element of the original structure.

The difference is that map works only for lists, fmap works for functors (that were covered in episode 2778) and mapM works for structures in monadic context.

Best way to contact me nowadays is either by email or through fediverse where I’m tuturto@mastodon.social.

HPR2795: Dead Earth

Apr 19, 2019


Full shownotes are on mixedsignals.ml

You can download Klaatu's update revision of the game materials here: https://mixedsignals.ml/download/deadearth-bundle-gfdl.7z

HPR2794: Interview with Martin Wimpress

Apr 18, 2019


Ubuntu, MATE.

Two words which, taken separately, refer to great products.

On one side, Ubuntu, one of the most popular, if not the most popular, linux distribution.

On the other side, the MATE desktop environment, also very popular.

One person took those two elements and combined them together to make Ubuntu MATE. That person is Martin Wimpress, and he joined me on the 21st of March to talk about the past, present, and future of the project.

HPR2793: bash coproc: the future (2009) is here

Apr 17, 2019


If you want the full manuscript, that’s at gitlab: hpr2793_bash_coproc_manuscript.adoc. It’s almost a transcript, but I added spontaneous commentary while reading the examples, so that’s not in the manuscript.

Episode errata:

Command substitution with $() is perfectly valid according to POSIX, and is accepted both by dash and by bash --posix. It’s not to be considered a bashism.

I fumbled the pronunciation of the printf format string in one place and said "parenthesis" instead of "percentage sign".

I tried to say "space" every time there’s a space, but I know I forgot it in a few places. But you probably need to look at the show notes to really make sense of the commands anyway.

Example #1:

$ echo $(echo hacker public radio) hacker public radio $ $(echo echo hacker public radio) # It can even supply the command itself, not just parameters. Note the word splitting. hacker public radio $ "$(echo echo hacker public radio)" # Counteract word splitting by putting the command substitution in quotes. bash: echo hacker public radio: command not found $ `echo echo hacker public radio` # Old-style command substitution hacker public radio

More on command substitution in Dave’s hpr1903: Some further Bash tips.

Example #2:

$ echo <(echo hacker public radio) /dev/fd/63 $ cat <(echo hacker public radio) hacker public radio

You can also combine process substitution with redirection.

Example #3:

$ echo hacker public radio > >(sed -e 's/$/!/') # You need the space between the greater-thans here! hacker public radio!

More on process substitution in Dave’s hpr2045: Some other Bash tips.

For a description of a hack for creating bidirectional anonymous pipes in bash, see my Fediverse post on this, and I owe you a show.

A coprocess in bash is a subshell to which you have access to two file descriptors: Its stdin and its stdout.

The two file descriptors will be put in a bash array. To learn more about arrays, check out Dave’s series within the bash series, a whopping five-part quadrology including hpr2709, hpr2719, hpr2729, hpr2739 and hpr2756.

You create a coprocess using the coproc keyword, brand spanking new since bash 4 from 2009. I am filing issues to pygments and GNU src-highlite to support it.

There are two ways to call coproc. The first way is to give coproc a simple command.

Example #4:

$ coproc :; declare -p COPROC [1] 25155 declare -a COPROC=([0]="63" [1]="60") [1]+ Done coproc COPROC :

The other way is to give coproc an explicit name and a Command Grouping.

Example #5:

$ coproc HPR (:); declare -p HPR [1] 25469 declare -a HPR=([0]="63" [1]="60") [1]+ Done coproc HPR ( : )

Slightly less contrived example #6:

$ coproc GREP (grep --line-buffered pub); printf '%s\n' hacker public radio >&${GREP[1]}; cat <&${GREP[0]} [1] 25627 public ^C $ kill %1 [1]+ Terminated coproc GREP ( grep --color=auto --line-buffered pub )

Here grep and cat wait forever for more input, so we have to kill them to continue our lesson.

But we know that GREP will only return one line, so we can just read that one line. And when we are done feeding it lines, we can close our side of its stdin, and it will notice this and exit gracefully.

I’m glad I stumbled over that {YOURVARIABLE}>&- syntax for having a dereferenced variable as the left FD of a redirection. Originally I used an ugly eval.

Example #7:

$ coproc GREP (grep --line-buffered pub); printf '%s\n' hacker public radio >&${GREP[1]}; head -n1 <&${GREP[0]}; exec {GREP[1]}>&- [1] 25706 public [1]+ Done coproc GREP ( grep --color=auto --line-buffered pub )

There we go! Not the most brilliant example, but it shows all the relevant moving parts, and we covered a couple of caveats.

Now go out and play with this and come back with an example on how this is actually useful in the real world, and submit a show!

HPR2792: Playing around with text to speech synthesis on Linux

Apr 16, 2019


Below the script I used to generate a bunch of wav files with different text to speech applications.

#!/bin/bash string="This is HPR episode 2792 entitled \"Playing around with text to speech synthesis on Linux\" and is part of the series \"Sound Scapes\". It is hosted by Yeroon Bahten and is about 20 minutes long and carries a clean flag." echo "${string}" > text.txt espeak -w espeak.wav "${string}" espeak -w espeak-ng-v-mb-us1.wav -v mb-us1 "${string}" espeak -w espeak-ng-v-mb-us2.wav -v mb-us2 "${string}" espeak -w espeak-ng-v-mb-us3.wav -v mb-us3 "${string}" espeak-ng "${string}" espeak-ng -v en-gb "${string}" espeak-ng -w espeak-ng-en-gb-scotland.wav -v en-gb-scotland "${string}" espeak-ng -w espeak-ng-en-us.wav -v en-us "${string}" flite -o flite-voice-cmu_us_slt.wav -voice cmu_us_slt "${string}" echo "${string}"| festival --language english --tts # same as next line echo "${string}"| text2wave --language british_english --tts -o festival_british_english.wav text2wave -o festival_british_english.wav text.txt for voice in don_diphone kal_diphone ked_diphone rab_diphone do text2wave -o festival_voice_${voice}.wav -eval "(voice_${voice} )" text.txt done # Gnustep say, recorded with audio recorder. say "${string}" text2wave -o festival_voice_cmu_us_slt_arctic_hts.wav -eval "(voice_cmu_us_slt_arctic_hts )" text.txt # merlin https://github.com/CSTR-Edinburgh/merlin # marytts: https://github.com/marytts

HPR2791: LUKS like truecrypt

Apr 15, 2019


Create an empty file of a predetermined size:

$ fallocate --length 512M foo.img

Create a LUKS container on it:

$ cryptsetup --verify-passphrase luksFormat foo.img

Set it up:

$ sudo cryptsetup luksOpen foo.img foo $ ls /dev/mapper foo $

Make a file system on it:

$ sudo mkfs.ext2 /dev/mapper/foo

If you don't need it for anything now, you can close it:

$ sudo cryptsetup luksClose foo $ ls /dev/mapper $

Mount it as a usable filesystem:

$ sudo mkdir /crypt $ sudo mount /dev/mapper/foo /crypt

Depending on your system configuration, you may need to set up reasonable permissions:

$ sudo mkdir /crypt/mystuff $ sudo chown klaatu:users /crypt/mystuff $ sudo chmod 770 /crypt/mystuff $ echo "hello world" >> /crypt/mystuff/file.txt

When you're finished using your encrypted vault, unmount and close it:

$ sudo umount /crypt $ sudo cryptsetup luksClose foo

HPR2789: Pacing In Storytelling

Apr 11, 2019


Some stories, that are otherwise cookie-cutter in form, possessing familiar situations and clichéd characters, seem to nonetheless stand out. Other tales that might have great ideas, intriguing plots, and vivid characters, seem to hit the ground with a thud. The determining value here may lie with the pacing of the story.

How does pacing (that is, timing) affect your story? Why does it matter? Can you make improvements in the pace by moving things around? What’s the best approach for creating it to begin with?

Lostnbronx meanders for a while, often losing his way, and rarely making a coherent point regarding this complicated topic.

HPR2788: Looping in Haskell

Apr 10, 2019


Haskell is functional language where data is immutable. This means that regular for-loops don’t really exist. Looping however is very common pattern in programs in general. Here are some patterns how to do that in Haskell.


Calculating Fibonacci numbers is common example (sort of like hello world in Haskell). There’s many different implementations at https://wiki.haskell.org/The_Fibonacci_sequence if you’re interested on having a look.

Simple recursive definition:

fibs :: Integer -> Integer fibs 0 = 0 fibs 1 = 1 fibs n = fibs (n-1) + fibs (n-2)

When called with 0 result is 0. When called with 1 result is 1. For all other cases, fibs is called with values n-1 and n-1 and the results are summed together. This works fine when n is small, but calculation gets slow really quickly with bigger values.

Another way is to define list of all Fibonacci numbers recursively:

allFibs :: [Integer] allFibs = 0 : 1 : zipWith (+) allFibs (tail allFibs)

Here a list is constructed. First element is 0, second element is 1 and rest of the list is obtained by summing the list with its tail (everything but the first element of the list). Definition is recursive and defines all Fibonacci numbers. However, Haskell doesn’t evaluate whole list, but only as much of it as is required.

Common pattern of processing elements in a list, producing a new list:

addOne :: [Integer] -> [Integer] addOne [] = [] addOne (x:xs) = x + 1 : addOne xs

Two cases, when called with an empty list [], result is empty list. For all other cases, list is taken apart (x:xs), x contains first element of the list and xs is rest of the list. Body of the function creates a new list where head is x + 1 and tail is addOne xs. This processes whole list of Integer by adding one to each value. It also reverses the list.

Second common pattern is processing a list and reducing it to a single value:

sumAll :: Integer -> [Integer] -> Integer sumAll n [] = n sumAll n (x:xs) = sumAll (n + x) xs

If given list is empty (the terminal case), result is n. Second case again takes list apart (x:xs), adds x and n together and recursive call sumAll with tail of the list.

This common pattern is discarding some elements of a list:

evenOnly :: [Integer] -> [Integer] evenOnly [] = [] evenOnly (x:xs) = if even x then x : evenOnly xs else evenOnly xs

Again, result of empty list is just empty list. In all other cases we first check if x is even. If so, new list is constructed where head is x and tail is evenOnly xs. If x isn’t even, it’s discarded and evenOnly is called recursively with tail of the list.

More tools

Writing recursion by hand gets tedious and sometimes confusing (if you listened to the show, you probably noticed how I got confused and had to check that evenOnly actually works as I thought it would). For that reason, there are tools that abstract these common patterns and given them names.

First is map. It applies given function to each element of a list, thus producing a new list:

> map (+1) [1..10] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] > map odd [1..10] [True, False, True, False, True, False, True, False, True, False]

Second is fold. There is good article at https://wiki.haskell.org/Foldr_Foldl_Foldl%27 that talks about differences between different folds.

The basic idea behind each fold is the same, they take a function and initial value and then apply them to first element of list, producing a value. This value is then applied with the function to the second element of the list and so on, until whole list has been reduced to a single value. Calculating a sum of list is so common operation that there’s specific function for that: sum.

> foldr (+) 0 [1..10] 55 > foldl (+) 0 [1..10] 55 > sum [1..10] 55

scan is similar to fold, except for returning only the final value, it also returns intermediate ones. Here it’s easier to observe how scanr and scanl differ from each other:

> scanr (+) 0 [1..10] [55,54,52,49,45,40,34,27,19,10,0] > scanl (+) 0 [1..10] [0,1,3,6,10,15,21,28,36,45,55]

Last of the trifecta is filter that is used to select some of the elements in a list based on a supplied function.

> filter odd [1..10] [1, 3, 5, 7, 9] > filter even [1..] [2, 4, 6, 8, 10, 12, 14, 16...] > take 5 $ filter even [1..] [2, 4, 6, 8, 10] Even more tools

There are even more tools at our disposal. Prelude is basic library of Haskell and browsing online documentation at http://hackage.haskell.org/package/base- might yield interesting information.

For example, constructing some lists:

iterate :: (a -> a) -> a -> [a] For list where function is applied repeatedly. repeat :: a -> [a] for a list that contains infinite amount of a. replicate :: Int -> a -> [a] For a list that contains finite amount of a. cycle :: [a] -> [a] For a infinite list that repeats same list over and over again. Finding tools

It’s all about knowing the right tools and finding them when needed. Luckily, you don’t have to memorize big stack of notes, but can turn to https://hoogle.haskell.org/ which is Haskell API search engine. It can search based on name or type signature. I often use it to find out if somebody has already written a function that I’m thinking of writing myself.

If you want to send questions or comments, I can be reached with email or at fediverse where I’m tuturto@mastodon.social. This episode is direct result of feedback that I got from previous one. If there’s Haskell topic you would love to hear more, drop me line or even better, research it by yourself and make a cool Hacker Public Radio episode.

HPR2787: NodeJS Part 1

Apr 9, 2019

HPR2786: My YouTube Channels

Apr 8, 2019


Hallo HPR listeners this is Tony Hughes again coming from Blackpool in the UK.

Recently Ahuka started a series on the YouTube channels that he subscribes to and this seems like a good topic to share some of my favourite YouTube channels. This time I’ll share some of the tech and Linux based channels I watch.

bigclive.com – Clive strips down and tests equipment particularly cheap Chinese electronics - https://www.youtube.com/user/bigclivedotcom/videos

Category5 Technology TV – A general technology based show with a large focus on Linux and open source software. https://www.youtube.com/user/category5tv

Explaining Computers – Exactly what it says on the tin, they review new computer hardware and computer related tech, including single board Computers such as the Raspberry Pi and Pine 64. https://www.youtube.com/user/explainingcomputers

DASGeek – Ryan is a fairly new person to Linux and is part of the Destination Linux podcast crew - https://destinationlinux.org/ Ryan is an avid gamer and as well as reviewing Linux he will often look at the latest games and how well they will work on a Linux PC. https://www.youtube.com/channel/UCIme1suHyN7cAGrTy8RBdhQ

Big Daddy Linux – A new video LUG which have a new episode every week at 8pm EST or you can watch a recording of the show later. https://www.youtube.com/channel/UCtZRKfyvx7GUEi-Lr7f4Nxg/videos

Raspberry Pi – Videos from the Foundation and community contributors. https://www.youtube.com/channel/UCFIjVWFZ__KhtTXHDJ7vgng/videos

Free Audacity Tutorials – Very handy for those of us that regularly record and edit audio with Audacity, for learning more about how to do various things with this software. https://www.youtube.com/user/FreeAudacityTutorial/videos

And finally for this episode

Linus Tech Tips – Another Computer review show all about tips and tricks relating to all stuff geeky. Be aware that this show is heavily sponsored although Linus does seem to be very fair with both praise and criticism for what he is reviewing. https://www.youtube.com/user/LinusTechTips/videos

HPR2784: The Yamaha Disklavier

Apr 4, 2019


In this episode I talk about the Yamaha Disklavier DKC500RW that's in my office at work. This is a very high-tech player piano and one of the coolest pieces of music gear I've ever seen.

Photo Album (click image)

Yamaha Disklavier

Links Website showing how to determine which model disklavier you have: Yamahaden DisklavierTM World: This is a privately operated, Public Service (non-profit) webpage. 10,781 piano-music files in 'FIL' (e-SEQ) & MIDI format & Software for the Yamaha Disklavier. PUBLIC-DOMAIN / 'Live' MIDI-Performances / FREE Sequences Video: Jonathan Kulp, Three Easy Pieces for Piano Four-Hands: Video of premiere performance Video: Disklavier in action

HPR2783: The Windows "Shutdown.exe" Command Explained

Apr 3, 2019


Shutdown.exe Introduced in Windows 2000 as a way to shutdown the PC via the command prompt. Included in all versions since Windows 2000 all the way to Windows 10 and Windows Server 2019. ReactOS, the open source binary-compatible clone of Windows, also includes the shutdown.exe command and the commands are the same. Located in %windir%\System32. The variable %windir% is usually c:\windows. In ReactOS, the variable is usually c:\reactos (failed to mention this in the recording).


https://ipfs.io/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Shutdown.exe.html https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/shutdown https://ss64.com/nt/shutdown.html https://en.wikipedia.org/wiki/Shutdown_(computing)#Windows_and_ReactOS

HPR2782: Never stop gaming

Apr 2, 2019


Shownotes are on mixedsignals.ml

HPR2781: HPR Community News for March 2019

Apr 1, 2019


New hosts

Welcome to our new hosts:
Floyd C Poynter, aldenp, minnix.

Last Month's Shows Id Day Date Title Host 2760 Fri 2019-03-01 What is VNF JWP 2761 Mon 2019-03-04 HPR Community News for February 2019 HPR Volunteers 2762 Tue 2019-03-05 What You Really Are lostnbronx 2763 Wed 2019-03-06 Deepgeek explains SPF records klaatu 2764 Thu 2019-03-07 Personal password algorithms klaatu 2765 Fri 2019-03-08 My YouTube Subscriptions #3 Ahuka 2766 Mon 2019-03-11 Disk enumeration on Linux klaatu 2767 Tue 2019-03-12 Djvu and other paperless document formats klaatu 2768 Wed 2019-03-13 Writing Web Game in Haskell - Planetary statuses tuturto 2769 Thu 2019-03-14 Quick Review of the AstroAI WH5000A Multimeter NYbill 2770 Fri 2019-03-15 Navigating the maze of RPG books klaatu 2771 Mon 2019-03-18 Embedding hidden text in Djvu files klaatu 2772 Tue 2019-03-19 My applications and software part 3 Tony Hughes AKA TonyH1212 2773 Wed 2019-03-20 Lead/Acid Battery Maintenance and Calcium Charge Voltage Floyd C Poynter 2774 Thu 2019-03-21 CJDNS and Yggdrasil aldenp 2775 Fri 2019-03-22 My YouTube Subscriptions #4 Ahuka 2776 Mon 2019-03-25 Sub-Plots In Storytelling lostnbronx 2777 Tue 2019-03-26 The quest for the perfect laptop. knightwise 2778 Wed 2019-03-27 Functor and applicative in Haskell tuturto 2779 Thu 2019-03-28 HTTP, IPFS, and torrents aldenp 2780 Fri 2019-03-29 My SBC Nextcloud Install Pt. 1 - Hardware minnix Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows.
There are 24 comments in total.

There are 3 comments on 3 previous shows:

hpr2708 (2018-12-19) "Ghostscript" by klaatu. Comment 2: Klaatu on 2019-03-07: "You're welcome"
hpr2749 (2019-02-14) "Lostnbronx and Klaatu commentary from episode 2743" by klaatu. Comment 1: Klaatu on 2019-03-07: "We are stupid"
hpr2759 (2019-02-28) "Cleaning the Potentiometers on a Peavey Bandit 65" by Jon Kulp. Comment 2: Jon Kulp on 2019-03-02: "Never too much about 80s gear"

There are 21 comments on 12 of this month's shows:

hpr2761 (2019-03-04) "HPR Community News for February 2019" by HPR Volunteers. Comment 1: Mike Ray on 2019-03-04: "Media embedded show notes"
hpr2762 (2019-03-05) "What You Really Are" by lostnbronx. Comment 1: tuturto on 2019-03-05: "oh, wow"
hpr2763 (2019-03-06) "Deepgeek explains SPF records" by klaatu. Comment 1: b-yeezi on 2019-03-09: "Thanks for the help"Comment 2: pauleb on 2019-03-11: "Great explanation!"
hpr2764 (2019-03-07) "Personal password algorithms" by klaatu. Comment 1: Steve on 2019-03-12: "LessPass"
hpr2766 (2019-03-11) "Disk enumeration on Linux" by klaatu. Comment 1: Joel D on 2019-03-12: "The Letters C and F"Comment 2: Klaatu on 2019-03-13: "Thanks for the info Joel"Comment 3: Ahuka on 2019-03-14: "Old drive letters"
hpr2768 (2019-03-13) "Writing Web Game in Haskell - Planetary statuses" by tuturto. Comment 1: Klaatu on 2019-03-15: "Agog and aghast"Comment 2: tuturto on 2019-03-15: "this made my week"
hpr2773 (2019-03-20) "Lead/Acid Battery Maintenance and Calcium Charge Voltage" by Floyd C Poynter. Comment 1: tuturto on 2019-03-20: "Good to know"Comment 2: Nybill on 2019-03-20: "Good Info"
hpr2774 (2019-03-21) "CJDNS and Yggdrasil" by aldenp. Comment 1: tuturto on 2019-03-21: "fascinating"Comment 2: Brian-in-Ohio on 2019-03-21: "more shows"Comment 3: norrist on 2019-03-21: "gentoo"Comment 4: Gavtres on 2019-03-25: "IPv6 end to end encryption"
hpr2776 (2019-03-25) "Sub-Plots In Storytelling" by lostnbronx. Comment 1: operat0r on 2019-03-25: "fun stuff"
hpr2777 (2019-03-26) "The quest for the perfect laptop." by knightwise. Comment 1: Beeza on 2019-03-29: "Computer Requirements Specification"
hpr2778 (2019-03-27) "Functor and applicative in Haskell" by tuturto. Comment 1: Beeza on 2019-03-28: "Intuitiveness Of Haskell"Comment 2: tuturto on 2019-03-29: "thanks and great idea"
hpr2779 (2019-03-28) "HTTP, IPFS, and torrents" by aldenp. Comment 1: Hipstre on 2019-03-31: "Enjoyed it, sounded great"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-March/thread.html Any other business Sorry Yannick!

There was a misunderstanding about Yannick’s show 2740 when it was discussed on the February Community News. The show was about Pop_OS!, a subject Yannick had also spoken about previously on an edition of the TuxJam podcast.

The misunderstanding was that we thought this might have gone against guidelines on syndication, where in fact it did not. It was merely a case of the same subject being spoken about by the same person on two different podcasts.

Change to the host page

The page for each host:


which used to contain a list of all shows contributed by that host, with the show notes, has been made more compact. It now displays only the title, release date, duration, series (if applicable), tags and the show summary. Clicking on the title takes you to the show itself.

The list of all hosts in alphabetic order can be seen at http://hackerpublicradio.org/correspondents.php (navigate with the top menu bar: Home→About→Hosts). From there clicking on the host number takes you to the page for that host. There’s also a link to the host page from the page for each show.

Community News Calendar

An iCal calendar has been prepared which holds the next 12 recording dates for the Community News. This calendar can be downloaded and opened by suitable clients such as the Thunderbird mail client or Google Calendar. The file is linked from http://hackerpublicradio.org/about.php and may be downloaded from http://www.hackerpublicradio.org/HPR_Community_News_schedule.ics.

Tags and Summaries

Thanks to the following contributors for sending in updates in the past month: Ken Fallon, NYbill, windigo

Over the period tags and/or summaries have been added to 32 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at http://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2780: My SBC Nextcloud Install Pt. 1 - Hardware

Mar 29, 2019


I explain the build process for my home Nextcloud server using a single board computer and a 4 bay RAID enclosure. This is part 1 of a 3 part series.

My parts list for the server build:


eMMC module

USB Adapter for eMMC module

Power supply


90˚ male to female USB extension

4 bay RAID enclosure

The 4TB HDDs were ones I already had but you can use any ones, just make sure they are the same brand/model/size/etc to minimize any complications.

minnix at uymail dot com for help, questions, or just general chatter

HPR2779: HTTP, IPFS, and torrents

Mar 28, 2019


Some ramblings about how we might replace HTTP with more robust, decentralized protocols.

https://en.wikipedia.org/wiki/InterPlanetary_File_System https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

HPR2778: Functor and applicative in Haskell

Mar 27, 2019


Two common patterns that I seem to run all the time while working on my 4x space game are functor and applicative. This episode explains them briefly.


Functor is a way to apply function over a structure we don’t want to alter. Type of the structure stays same, but values inside of it can change. One of the most common one is list, but there are many others.

Functor type class is defined below. There’s one function fmap that takes two parameters: a function from a to b and structure f a. Result will be structure f b.

class Functor f where fmap :: (a -> b) -> f a -> f b

This is fairly abstract, so couple example might help. First we define a little helper function that raises it’s argument to 2nd power (in the episode I talk about doubling the value, my mistake there).

-- | this really raises x to 2nd power and doesn't double it double x = x * x

Given a list of Int we can raise them to power of two by using fmap:

> fmap double [1, 2, 3, 4, 5] [1, 4, 9, 16, 25]

Since function being applied to structure is type of (a -> b), we can change type of the value inside of the structure. Below is example of turning list of Int to list of Text.

> fmap show [1, 2, 3, 4, 5] ["1", "2", "3", "4", "5"]

This pattern isn’t limited to list and there are many others. You can even define your own ones, if you’re so inclined. The pattern stays the same. One function, fmap, that takes function of type (a -> b) and structure f a and turns it into structure of f b. Details how this is actually done depend on the specific functor.

Other common functor is Maybe that is often used in cases where data might or might not be present. Maybe a has two possible values Just a indicating that value a is present and Nothing indicating that there is no value present. When fmap is used in this context, Just a will turn to Just b and Nothing will stay as Nothing.

> fmap (x -> x * x) $ Just 2 Just 4 > fmap (x -> x * x) Nothing Nothing

Either a b is sometimes used for value that can be correct or an error. It has two value constructors Right b indicates that value is correct, Left a indicates an error case. a and b don’t have to be of same type (and usually aren’t). For example, if we have Either Text Int, then we have value where error case is Text and correct value is Int.

> fmap double $ Right 5 Right 25 > fmap double $ Left "distance calculation failed because of flux-capacitor malfunction" Left "distance calculation failed because of flux-capacitor malfunction"

Functors can be placed inside of functors. The only difference is that you have to reach through multiple layers. Simplest way of doing that is to compose multiple fmap functions together like in the example below. Pay attention to in which order nested functors are defined as Maybe [Int] and [Maybe Int] are different things. Former is for case where list of Int might or might not be present. Latter is for case where there’s always list, but single element inside of the list might or might not be present.

> (fmap . fmap) double (Just [1, 2, 3, 4]) Just [1, 4, 9, 16] > (fmap . fmap) double Nothing :: Maybe Int Nothing > (fmap . fmap) double [Just 1, Just 2, Nothing, Just 3] [Just 1, Just 4, Nothing, Just 9]

There’s also infix operator, that does exactly same thing as fmap, called <$>. The choice which one to use is often either personal or depends on the surrounding code (because Haskell doesn’t use parenthesis in function application, so sometimes it’s easier to use fmap and sometimes <$>).

> fmap show [1, 2, 3, 4, 5] ["1", "2", "3", "4", "5"] > show <$> [1, 2, 3, 4, 5] ["1", "2", "3", "4", "5"]

There are many more functors, one place to check them is: https://hackage.haskell.org/package/base-


While functor works fine when function applied has only one paramere, we need applicative in cases of multiparameter functions. Calling fmap (+) [1, 2] will produce list of functions waiting for second parameter. While it would be possible to handle these cases manually, we like to abstract it to more general solution.

class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b

Applicative is similar to functor. The big difference is that function being applied is now embedded inside of same type of structure. While functor has (a -> b), applicative has f (a -> b).

Below is an example of using list applicative to calculate all possible ways of summing two lists of Int.

> (+) <$> [1, 2, 3] <*> [4, 5, 6] [5,6,7,6,7,8,7,8,9]

Maybe Int works with the same pattern. First we use <$> to get started, this results Maybe containing a function that is waiting for second parameter. Then we use <*> to apply the second parameter so we get the result.

> (+) <$> Just 2 <*> Just 5 Just 7 > (+) <$> Just 2 <*> Nothing Nothing

As long as there’s only Just a in play, result is Just, but as soon as there’s even single Nothing the end result will be nothing.

If you have questions or comments, I would be delighted to hear about them. You can catch me on fediverse, where I’m tuturto@mastodon.social. Even better, you could record your own HPR episode.

Ad astra!

HPR2777: The quest for the perfect laptop.

Mar 26, 2019


Looking for a new laptop.


HP Envy x360 Lenovo X280 Lenovo X380 Lenovo X380 Yoga Lenovo X1 Lenovo X1 Yoga

HPR2776: Sub-Plots In Storytelling

Mar 25, 2019


What makes for strong subplots? Why can some subplots be chopped out of a tale without harming it? Why can some be chopped out, and it actually makes the tale stronger? Is this modular approach the best way to bring in subplots, or is there another method that might be better?

Story construction is a complicated topic; Lostnbronx tries (and largely fails) to make sense of this small part of it.

HPR2775: My YouTube Subscriptions #4

Mar 22, 2019


I am subscribed to a number of YouTube channels, and I am sharing them with you

The HollyHobs - https://www.youtube.com/channel/UCkhSH-DB2xK4BIJZoql9djQ Adam Neely - https://www.youtube.com/channel/UCnkp4xDOwqqJD7sSM3xdUiQ Airstream of Scottsdale - https://www.youtube.com/channel/UChNNDq91qW6zDkUXM2IuIYQ Alternate History Hub - https://www.youtube.com/channel/UClfEht64_NrzHf8Y0slKEjw Alton Brown - https://www.youtube.com/channel/UCfDNi1aEljAQ17mUrfUjkvg Apartment Sessions - https://www.youtube.com/channel/UCpU_PAsVFl2fO649QF6Zj0Q AStreaminLife - https://www.youtube.com/channel/UCtrZvxP1SQkBJ8kZLsslimw Big Truck Big RV - https://www.youtube.com/channel/UCaX2-JkluLd8aG0DXp0L2Xw Bill Holbrook - https://www.youtube.com/channel/UChE4ujkOdzJ02k-F9ZqwpMw CGP Grey - https://www.youtube.com/channel/UC2C_jShtL725hvbm1arSV9w Crash Course - https://www.youtube.com/channel/UCX6b17PVsYBQ0ip5gyeme-Q Deep Sky Videos - https://www.youtube.com/channel/UCo-3ThNQmPmQSQL_L6Lx1_w Doctor Who - https://www.youtube.com/channel/UCcOkA2Xmk1valTOWSyKyp4g Emperor Tigerstar - https://www.youtube.com/channel/UCUXqYwTCR6R3Wr-FkLTD4AQ Fastway Trailer - https://www.youtube.com/channel/UCDKtrIOnj4IvatnpJkh2aXA fyfluiddynamics - https://www.youtube.com/channel/UCxuET3jfy0v8EJa7TKNiI2g Haylett RV - https://www.youtube.com/channel/UCRS9u1f7074u0Rrgu05K9Wg It’s OK To Be Smart - https://www.youtube.com/channel/UCH4BNI0-FOK2dMXoFtViWHw Less Junk, More Journey - https://www.youtube.com/channel/UC2IENUorXc6kRtIiAGPRKZA Long, Long Honeymoon - https://www.youtube.com/channel/UCw5WYtMXQ799GErKpvR_5Rw Matt’s RV Reviews - https://www.youtube.com/channel/UCBHww2yk8soPJ9IcbZ0n_Uw https://www.palain.com/

HPR2774: CJDNS and Yggdrasil

Mar 21, 2019


This is my first time doing this sort of thing, so I’m sorry if it’s not very good.

https://github.com/cjdelisle/cjdns/ https://yggdrasil-network.github.io/

HPR2773: Lead/Acid Battery Maintenance and Calcium Charge Voltage

Mar 20, 2019


Although Lead/Acid batteries are old tech, the use of Calcium as an alloy metal has been a more modern development. Unfortunately many people do not realize this causes an incompatibility with older vehicles due to charging voltage. This episode discusses the use of smart chargers for long term battery maintenance.

HPR2772: My applications and software part 3

Mar 19, 2019


Hallo HPR listeners – in my recent episodes hpr2738 and hpr2746 I talked about some of the applications and software I regularly use as part of my day to day use of Linux Mint. This follow up show will continue with a few more of the same.

CUPS – Common Unix Printing Software; printing in Linux with this utility is fairly well supported, if you don’t have a very recent printer it’s a good chance that CUPS will be able to find a driver for your printer if a Linux one has not been supplied when you bought it or through the manufacturers support site. In the menu just search for print and it will bring up the application for adding a new printer.

Gparted – fully featured disc management tool for formatting and partitioning discs

Document viewer – generic pdf viewer

Software manager

Synaptic package manager

Terminal – apt command for updating the system and installing new software


HPR2771: Embedding hidden text in Djvu files

Mar 18, 2019


To embed text into a Djvu file, you must create a djvused script detailing the page and bitmap location of one of: character, word, line, paragraph, or region.

For good measure, you should first list the contents of your Djvu bundle:

$ djvused -e 'select; ls' test.djvu 1 P 177062 p0001.djvu 2 P 199144 p0002.djvu 3 P 12323 p0003.djvu 4 P 57059 p0004.djvu 5 P 96725 p0005.djvu 6 P 53868 p0006.djvu

Then define the location of text in a file called, for instance, content.dsed. Assume that my page is 1000 px by 1000 px:

select; remove-ant; remove-txt select "p0004.djvu" # page 4 set-txt (page 0 0 1000 1000 (word 100 600 450 800 "Hello" ) (word 100 600 450 800 "world" )) . select "p0005.djvu" set-txt (page 0 0 1000 1000 (line 100 400 900 600 "Hacker Puppy Radio"))

Apply this script to your Djvu file with dvjused:

djvused -f ./content.dsed -s test.djvu Converting from PDF to Djvu

You can convert PDF files to Djvu with the djvudigital command. Due to license incompatibility, it does require you to compile a Ghostscript plugin, but it's an easy build. Get the gsdjvu code, and then follow its README instructions.

Once you've built the Ghostscript driver, you can convert PDF to Djvu:

djvudigital --words foo.pdf foo.djvu

HPR2770: Navigating the maze of RPG books

Mar 15, 2019


Taxonomy of RPG-related books:

Rulebooks tell you how to play the game.

Optional books of rules add modular components to the base game. They add nuance to specific actions (for example, a book might add rules on owning and managing a castle in a fantasy world, or it might add rules on hacking in a sci fi game; these are things you can do without rules in the game, but if you want added stakes, then these books are ones you would want to obtain).

Adventures (formerly called "modules") provide game plots and locations, in the event that you have no interest in designing your own.

Source books or "settings" provide additional information on the setting of a game, sometimes even providing an alternate game universe with additional rules.

Extra media, like novels, comics, movies, and video games, provide more information (sometimes in canon, sometimes not) about the game universe in which you are playing. Rarely do these have impact on the rules of the game, but they may provide a common language and shared experience for the players.

The only essential purchase is the rulebook. Everything else can be generated by gamers. Purchasing additional material is optional, and can either be seen as a great way to support a company providing your entertainment, or as an insidious plot by greedy corporations to rope you into a perpetual cycle of capitalism. However, RPG is a pretty healthy (and often open) system, so free and open content abounds.

HPR2769: Quick Review of the AstroAI WH5000A Multimeter

Mar 14, 2019


NYbill does yet another inexpensive multimeter review. This time the AstroAI WH5000A. (Its time for a multimeter intervention!)

The meter:


Pics for the episode:


HPR2768: Writing Web Game in Haskell - Planetary statuses

Mar 13, 2019



In episode hpr2748 Writing Web Game in Haskell - Special events, I talked about how to add special events in the game. One drawback with the system presented there was that the kragii worms might attack planet that already had kragii worms present. This time we’ll look into how to prevent this. As a nice bonus, we also come up with system that can be used to record when a planet has particularly good harvest season.

Data types and Database

We need a way to represent different kinds of statuses that a planet might have. These will include things like on going kragii attack or a particularly good harvest season. And since these are will be stored in database, we are also going to use derivePersistField to generate code needed for that.

data PlanetaryStatus = GoodHarvest | PoorHarvest | GoodMechanicals | PoorMechanicals | GoodChemicals | PoorChemicals | KragiiAttack derivePersistField "PlanetaryStatus"

We could have recorded statuses as strings, but declaring a separate data type means that compiler can catch typos for us. It also makes code easier to read as PlanetaryStatus is much more informative than String or Text.

For database, we use following definition shown below in models file. It creates database table planet_status and respective Haskell data type PlanetStatus. There will be one row in database for each status that a planet has. I could have stored all statuses in a list and store that in database, effectively having one row for any planet. Now there’s one row for any planet + status combination. Choice wasn’t really based on any deep analysis, but merely a gut feeling that this feels like a good idea.

PlanetStatus json planetId PlanetId status PlanetaryStatus expiration Int Maybe deriving Show Read Eq

expiration column doesn’t have NOT NULL constraint like all other columns in the table. This is reflected in PlanetStatus record where data type of planetStatusExpiration is Maybe Int instead of Int. So some statuses will have expiration time, while others might not. I originally chose to represent time as Int instead of own data type, but I have been recently wondering if that was really a good decision.

Kragii attack, redux

Code that does actual database query looks pretty scary on a first glance and it’s rather long. First part of the code is there to query database and join several tables into the query. Second part of the code deals with counting and grouping data and eventually returning [Entity Planet] data that contains all planets that match the criteria.

-- | Load planets that are kragii attack candidates kragiiTargetPlanets :: (MonadIO m, BackendCompatible SqlBackend backend , PersistQueryRead backend, PersistUniqueRead backend) => Int -> Int -> Key Faction -> ReaderT backend m [Entity Planet] kragiiTargetPlanets pop farms fId = do planets <- E.select $ E.from $ (planet `E.LeftOuterJoin` population `E.LeftOuterJoin` building `E.LeftOuterJoin` status) -> do E.on (status E.?. PlanetStatusPlanetId E.==. E.just (planet E.^. PlanetId) E.&&. status E.?. PlanetStatusStatus E.==. E.val (Just KragiiAttack)) E.on (building E.?. BuildingPlanetId E.==. E.just (planet E.^. PlanetId)) E.on (population E.?. PlanetPopulationPlanetId E.==. E.just (planet E.^. PlanetId)) E.where_ (planet E.^. PlanetOwnerId E.==. E.val (Just fId) E.&&. building E.?. BuildingType E.==. E.val (Just Farm) E.&&. E.isNothing (status E.?. PlanetStatusStatus)) E.orderBy [ E.asc (planet E.^. PlanetId) ] return (planet, population, building) let grouped = groupBy ((a, _, _) (b, _, _) -> entityKey a == entityKey b) planets let counted = catMaybes $ fmap farmAndPopCount grouped let filtered = filter ((_, p, f) -> p >= pop || f >= farms) counted let mapped = fmap ((ent, _, _) -> ent) filtered return mapped

In any case, when we’re querying for possible kragii attack candidates, the query selects all planets that are owned by a given faction and have population of at least 10 (left outer join to planet_population table), have at least 5 farming complex (left outer join to building table) and don’t have on going kragii attack (left outer join to planet_status table). This is encapsulated in kragiiTargetPlanets 10 5 function in the kragiiAttack function shown below.

Rest of the code deals with selecting a random planet from candidates, inserting a new planet_status row to record that kragii are attacking the planet and creating special event so player is informed about the situation and can react accordingly.

kragiiAttack date faction = do planets <- kragiiTargetPlanets 10 5 $ entityKey faction if length planets == 0 then return Nothing else do n <- liftIO $ randomRIO (0, length planets - 1) let planet = maybeGet n planets let statusRec = PlanetStatus <$> fmap entityKey planet <*> Just KragiiAttack <*> Just Nothing _ <- mapM insert statusRec starSystem <- mapM (getEntity . planetStarSystemId . entityVal) planet let event = join $ kragiiWormsEvent <$> planet <*> join starSystem <*> Just date mapM insert event

Second piece to the puzzle is status removal. In can happen manually or automatically when the prerecorded date has passed. Former method is useful for special events and latter for kind of seasonal things (good harvest for example).

For example, in case of removing kragii attack status, code below serves as an example. The interesting part is deleteWhere that does actual database activity and removes all KragiiAttack statuses from given planet.

removeNews event odds = MaybeT $ do res <- liftIO $ roll odds case res of Success -> do _ <- lift $ deleteWhere [ PlanetStatusPlanetId ==. kragiiWormsPlanetId event , PlanetStatusStatus ==. KragiiAttack ] _ <- tell [ WormsRemoved ] return $ Just RemoveOriginalEvent Failure -> do _ <- tell [ WormsStillPresent ] return $ Just KeepOriginalEvent

Removal of expired statuses is done based on the date, by using <=. operator to compare expiration column to given date.

_ <- deleteWhere [ PlanetStatusExpiration <=. Just date] Other uses and further plans

Like mentioned before, planet statuses can be used for variety of things. One such application is recording particularly good (or poor) harvest season. When such thing occurs, new planet_status record is inserted into database with expiration to set some suitable point in future. System will then automatically remove the status after that date is reached.

In the meantime, every time food production is calculated, we have to check for possible statuses that might affect it and take them into account (as form of small bonus or malus).

While this system is for planet statuses only, similar systems can be build for other uses (like statuses that affect a single ship or whole star system).

Easiest way to catch me nowadays is either via email or on fediverse where I’m tuturto@mastodon.social

HPR2767: Djvu and other paperless document formats

Mar 12, 2019


DjVu is a digital document format with advanced compression technology. DjVu allows for the distribution of very high resolution images of scanned documents, digital documents, and photographs. DjVu viewers are available for the web browser (search for djvujs in Firefox for an extension), the desktop ( Evince, Okular an BSD/Linux, and djview on BSD/Linux/Windows/Mac), and mobile devices.

The toolchain for encoding and decoding DjVu is djvulibre

djvu.js is a Javascript library useful for online viewing.

djvu.org contains sample documents and specification documents.

Creating a djvu file

The tool you use to convert something to the .djvu format depends on your requirements. If you're converting a basic, black-and-white document, then cjb2 (part of the djvulibre distribution) works:

$ cjb2 -dpi 300 foo.tiff $ ls foo.tiff foo.djvu

If you want to convert something more complex, then use c44 (also a part of the djvulibre distribution):

$ c44 -dpi 300 bar.jpg bar.djvu $ ls bar.jpg bar.djvu

To put both of these files in a single DjVu container:

$ djvm -c baz.djvu foo.djvu bar.djvu $ ls bar.djvu baz.djvu foo.djvu

You can add bookmarks, too. Open a text file called book.marks (or any name you prefer) and enter:

(bookmarks ("Foo" "#1") ("Bar" "#2") )

And then apply it to your DjVu file:

$ djvused -e 'set-outline book.marks' -s baz.djvu

There's more you can do with DjVu, but this has been an overview of how I use it.

HPR2766: Disk enumeration on Linux

Mar 11, 2019


The old way:

$ ls /dev/sd*

Another old way:

$ fdisk --list

An old way to see what you just plugged in:

$ sudo dmesg | tail

Some new tricks:

$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 2.7T 0 disk ├─sda1 8:1 0 23.3G 0 part └─sda2 8:2 0 2.7T 0 part sdb 8:16 0 3.9G 0 disk sdc 8:32 0 111.8G 0 disk ├─sdc1 8:33 0 100M 0 part /boot/efi └─sdc2 8:34 0 111.7G 0 part / sdd 8:48 0 1.8T 0 disk ├─sdd1 8:49 0 120G 0 part /var ├─sdd2 8:50 0 120G 0 part /tmp ├─sdd3 8:51 0 60G 0 part /opt └─sdd4 8:52 0 1.5T 0 part /home sde 8:64 0 298.1G 0 disk ├─sde1 8:65 0 500M 0 part ├─sde2 8:66 0 296.8G 0 part └─sde3 8:67 0 826M 0 part sdf 8:80 0 931.5G 0 disk └─sdf1 8:81 0 931.5G 0 part sdg 8:96 1 7.5G 0 disk └─sdg1 8:97 1 7.5G 0 part

User-friendly udisks:

$ udisks --monitor /dev Ctrl-c $ udisk --enumerate | sort /org/freedesktop/UDisks/devices/sda /org/freedesktop/UDisks/devices/sda1 /org/freedesktop/UDisks/devices/sda2 /org/freedesktop/UDisks/devices/sdb /org/freedesktop/UDisks/devices/sdc /org/freedesktop/UDisks/devices/sdc1 [...] $ udisks --mount /dev/sdc1 Mounted /dev/sdc1 on /media/mythumbdrive $ udisks --unmount /dev/sdc1

HPR2765: My YouTube Subscriptions #3

Mar 8, 2019


I am subscribed to a number of YouTube channels, and I am sharing them with you

Jennie Breeden - https://www.youtube.com/channel/UCMwWHArL7o7n-So1r-T_u3w Kate Techtonics - https://www.youtube.com/channel/UC4uxJvPa2nGe1ItPJsz2ORg Lydian Collective - https://www.youtube.com/channel/UCGFAwyexOW5Vi24zvYOSc-A Metropole Orkest - https://www.youtube.com/channel/UClOuC_V57_bW5sZ5yuh2IKw Mike Pachelli - https://www.youtube.com/channel/UCHnZrxYdMc0lNk8kEZVUoTA Mortons on the Move - https://www.youtube.com/channel/UCirNI5XV3xZZApeIe0a5-6Q Nixie Pixel - https://www.youtube.com/channel/UCBE-FO9JUOghSysV9gjTeHw Numberphile - https://www.youtube.com/channel/UCoxcjq-8xIDTYp3uz647V5A Nature Video - https://www.youtube.com/channel/UC7c8mE90qCtu11z47U0KErg Piled Higher and Deeper - https://www.youtube.com/channel/UCUL-pmhmDcZDwsA4cX2HO5w Postmodern Jukebox - https://www.youtube.com/channel/UCORIeT1hk6tYBuntEXsguLg RV Geeks - https://www.youtube.com/channel/UC2EOriLgUuwQn-uCHl58m_Q RVtravel - https://www.youtube.com/channel/UCARpsGWj6MJ7JE78OcfWKWw Science News - https://www.youtube.com/channel/UCBX5er6E37_yWB3gCM32p3g SciShow - https://www.youtube.com/channel/UCZYTClx2T1of7BRZ86-8fow SciShow Space - https://www.youtube.com/channel/UCrMePiHCWG4Vwqv3t7W9EFg Sophie Alloway - https://www.youtube.com/channel/UCCwcpSK-9Zbo8QDsPWdM1Bg Ten Minute History - https://www.youtube.com/channel/UC22BdTgxefuvUivrjesETjg The Fab Faux - https://www.youtube.com/channel/UCsU8AeRj_497u2IMxVA6OcQ https://www.palain.com/

HPR2764: Personal password algorithms

Mar 7, 2019


Here is a bash script to generate an org-mode word list matrix. It requires at least one file ending in .list to be used as a source of words or strings.

#!/bin/bash if [ -z $1 ]; then DEST=matrix.org else DEST=$1 fi cat >> "${DEST}" <<EOF | | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z | ? | |-+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---| EOF VERT=(a b c d e f g h i j k l m n o p q r s t u v w x y z ?) cat *list > tmp || exit BIG=`wc -l tmp | cut -f1 -d' '` c="0" while [ "$c" -lt "27" ]; do # horizontal row across n="0" v=`echo ${VERT[$c]}` printf "| $v |" >> "${DEST}" while [ "$n" -lt "27" ]; do i=`echo $((1 + RANDOM % $BIG))` w=`awk "FNR==$i" tmp` #reduce chance of empty cell if [[ -z $w ]]; then i=`echo $((1 + RANDOM % $BIG))` w=`awk "FNR==$i" tmp` echo "blank cell found" fi printf "$w | " >> "${DEST}" n=$[$n+1] done echo " " >> "${DEST}" c=$[$c+1] done /usr/bin/rm tmp

When you open the resulting file (matrix.org by default) in emacs, use the fill-paragraph (m-x fill-paragraph) function to align the cells into a pretty table.

Invent your own key, and generate some test passwords. Do this 6 or 8 times, and then try to reverse the key using the passwords and the table. If the logic to reverse the key is too simple, then try using values relying on the metadata, rather than data, of the table (for instance, the number of letters in the first word in the table starting with the same letter as the site name, or whatever).

Do you have analogue methods of generating passwords? Post ideas to either the comments or, better yet, as an HPR episode!

Here is a word list for testing:

HPR2763: Deepgeek explains SPF records

Mar 6, 2019


Klaatu reads a phlog (gopher) post by Deepgeek explaining the practical uses of SPF records.

HPR2762: What You Really Are

Mar 5, 2019


I got into Dungeons & Dragons back in the 1970s. This is my memory of that time and that gaming group, and especially, of the guy who taught me how to play.

HPR2761: HPR Community News for February 2019

Mar 4, 2019


New hosts

There were no new hosts this month.

Last Month's Shows Id Day Date Title Host 2740 Fri 2019-02-01 Pop!_OS 18.10 (quick) review Yannick the french guy from Switzerland 2741 Mon 2019-02-04 HPR Community News for January 2019 HPR Volunteers 2742 Tue 2019-02-05 SAP Hana Certification Directory JWP 2743 Wed 2019-02-06 Character build in the d20 system klaatu 2744 Thu 2019-02-07 Yet Another Rambling Drive Into Work MrX 2745 Fri 2019-02-08 My YouTube Subscriptions #1 Ahuka 2746 Mon 2019-02-11 My software part 2 Tony Hughes AKA TonyH1212 2747 Tue 2019-02-12 checking oil brian 2748 Wed 2019-02-13 Writing Web Game in Haskell - Special events tuturto 2749 Thu 2019-02-14 Lostnbronx and Klaatu commentary from episode 2743 klaatu 2750 Fri 2019-02-15 Windmill is on the Fritz Ken Fallon 2751 Mon 2019-02-18 Battling with English - part 3 Dave Morriss 2752 Tue 2019-02-19 XSV for fast CSV manipulations - Part 2 b-yeezi 2753 Wed 2019-02-20 Specific Settings In Storytelling lostnbronx 2754 Thu 2019-02-21 Craigslist Scam Catch Edward Miro / c1ph0r 2755 Fri 2019-02-22 My YouTube Subscriptions #2 Ahuka 2756 Mon 2019-02-25 Bash Tips - 20 Dave Morriss 2757 Tue 2019-02-26 How to DM klaatu 2758 Wed 2019-02-27 Haskell - Data types and database actions tuturto 2759 Thu 2019-02-28 Cleaning the Potentiometers on a Peavey Bandit 65 Jon Kulp Comments this month

These are comments which have been made during the past month, either to shows released during the month or to past shows.
There are 10 comments in total.

There are 6 comments on 5 previous shows:

hpr2672 (2018-10-30) "Porteus" by klaatu. Comment 3: clacke on 2019-02-26: "Re: Test-driving Linux in computer stores"
hpr2706 (2018-12-17) "Why I love the IBM AS/400 computer systems" by Jeroen Baten. Comment 4: Rob on 2019-02-27: "hpr2706 - episode about AS/400"
hpr2707 (2018-12-18) "Steganalysis 101" by Edward Miro / c1ph0r. Comment 3: rtsn on 2019-02-05: "!"
hpr2708 (2018-12-19) "Ghostscript" by klaatu. Comment 1: Steve on 2019-02-07: "Just what I needed"
hpr2737 (2019-01-29) "My Pioneer RT-707 Reel-to-Reel Tape Deck" by Jon Kulp. Comment 6: VulcanRidr on 2019-02-06: "Excellent!" Comment 7: Jon Kulp on 2019-02-06: "the RT-909"

There are 4 comments on 4 of this month's shows:

hpr2741 (2019-02-04) "HPR Community News for January 2019" by HPR Volunteers. Comment 1: Brian in Ohio on 2019-02-06: "show notes"
hpr2743 (2019-02-06) "Character build in the d20 system" by klaatu. Comment 1: tuturto on 2019-02-06: "Pleasure to listen to"
hpr2754 (2019-02-21) "Craigslist Scam Catch" by Edward Miro / c1ph0r. Comment 1: klaatu on 2019-02-27: "this episode"
hpr2759 (2019-02-28) "Cleaning the Potentiometers on a Peavey Bandit 65" by Jon Kulp. Comment 1: NYbill on 2019-02-28: "Stepping on toes!"
Mailing List discussions

Policy decisions surrounding HPR are taken by the community as a whole. This discussion takes place on the Mail List which is open to all HPR listeners and contributors. The discussions are open and available on the HPR server under Mailman.

The threaded discussions this month can be found here:

http://hackerpublicradio.org/pipermail/hpr_hackerpublicradio.org/2019-February/thread.html Any other business Tags and Summaries

Thanks to the following contributors for sending in updates in the past month: windigo

Over the period tags and/or summaries have been added to 24 shows which were without them.

If you would like to contribute to the tag/summary project visit the summary page at https://hackerpublicradio.org/report_missing_tags.php and follow the instructions there.

HPR2760: What is VNF

Mar 1, 2019

HPR2759: Cleaning the Potentiometers on a Peavey Bandit 65

Feb 28, 2019


Since my daughter has been learning a bit of guitar in the last several months, I've actually gotten my old electric guitar and amplifier back out again after many years in the closet. The amp is a Peavey Bandit 65, which was a an affordable solid-state workhorse kind of amp back in the mid-80s and I've had it since it was new. In this episode I talk through the process of removing the brains of the amp and cleaning the potentiometers to try to get rid of some of the static that's happening when I turn the knobs. I also discover belatedly that the reason I was not getting any distortion when I turned the saturation up was that the amp was stuck on the clean channel — shows how long it's been since I used the amp, I kind of forgot how the thing works!

Click image below to view photo gallery

Peavey Bandit 65 Cleaning

Links Peavey Electronics Corporation The Fender Stratocaster Credits Music bumpers are from Kimiko Ishizaka's The Open Goldberg Variations: http://www.opengoldbergvariations.org/, used by permission of their CC0 1.0 Universal (CC0 1.0) Public Domain Dedication license.

HPR2758: Haskell - Data types and database actions

Feb 27, 2019



I have been doing series about web programming in Haskell and realized that I might have skipped over some very basic details. Better later than never, I’ll go over some of them briefly (data types and database actions). Hopefully things will make more sense after this (like with my friend, whose last programming course was programming 101 and they said afterwards that now all that 3d and game programming is suddenly making sense).

Data types

Data here has nothing to do with databases (yet). This is how you can declare your own data types in Haskell. They’re declared with keyword data followed with type name, equals sign and one or more value constructors. Type name and value constructors have to start with uppercase letter.

Simplest type is following:

data Simple = One

This declares a type called Simple that has single possible value: One.

More interesting type is shown below. Colour has three possible values: Red, Green and Blue.

data Colour = Red | Green | Blue

It’s possible to have parameters in value constructor. Following is Payment type that could be used to indicate how payment was done. In case of Cash amount is stored. In case of IOU free text is recorded.

data Payment = Cash Double | IOU Text

Fictional usage of the Payment is shown below. Function paymentExplanation takes a Payment as parameter and returns Text describing the payment. In case of cash payment, brief explanation of how much was paid is returned. In case of IOU slip the function returns explanation stored in IOU value.

paymentExplanation :: Payment -> Text part is type declaration. It states that paymentExplanation takes argument of type Payment and returns result as Text.

paymentExplanation :: Payment -> Text paymentExplanation payment = case payment of Cash amount -> "Cash payment of " <> (show amount) <> " euros" IOU explanation -> explanation

Parameters don’t have to be hard coded in the type definition. Parametrized types allows creating more general code. Maybe is very useful data type that is often used for data that might or might not be present. It can have two values: Nothing indicating that there isn’t value and Just a indicating that value is present.

data Maybe a = Nothing | Just a

a is type parameter that is filled in when declaring type. Below is a function that takes Maybe Payment as a parameter and if value of payment parameter is Just returns explanation of it (reusing the function we declared earlier). In case of Nothing "No payment to handle" is returned.

invoice :: Maybe Payment -> Text invoice payment = case payment of Just x -> paymentExplanation x Nothing -> "No payment to handle"

Alternatively one can omit case expression as shown below and write different value constructors directly as parameters. In both cases, compiler will check that programmer has covered all cases and emit a warning if that’s not the case.

invoice :: Maybe Payment -> Text invoice (Just payment) = paymentExplanation payment invoice Nothing = "No payment to handle"

Having several parameters gets soon unwieldy, so lets introduce records. With them, fields have names that can be used when referring to them (either when creating or when accessing the data). Below is Person record with two fields. personName is of type Text and personAge of type Age (that we’ll define in the next step).

data Person = Person { personName :: Text , personAge :: Age }

To access data in a record, just use field as a function (there’s a bug, I’m turning 40, this month (today even, to be specific, didn’t realize this until I was about to upload the episode), but forgot such a minor detail when recording the episode):

me = Person { personName = "Tuukka", personAge = 37 } myAge = personAge me myName = personName me

New type is special type of record that can has only one field. It is often used to make sure one doesn’t mix similar data types (shoe size and age can both be Ints and thus mixed if programmer isn’t being careful). Compiler will optimize new types away during compilation, after checking that they’re being used correctly. This offers a tiny performance boost and makes sure one doesn’t accidentally mix different things that happen to look similar.

newtype Age = { getAge :: Int }

One can instruct compiler to derive some common functions for the data types. There are quite many of these, but the most common ones I’m using are Show (for turning data into text), Read (turning text into data) and Eq (comparing equality).

data Payment = Cash Double | IOU Text deriving (Show, Read, Eq) Database

In case of Yesod and Persistent, database structure is defined in models file that usually located in config directory. It is read during compile time and used to generate data types that match the database. When the program starts up, it can check structure of the database and update it to match the models file, if migrations are turned on. While this is handy for development, I wouldn’t dare to use it for production data.

Following definitions are lifted from the models file of the game I’m working.

StarSystem name Text coordX Int coordY Int deriving Show Read Eq

This defines a table star_system with columns id, name, coord_x, coord_y. All columns have NOT NULL constraint on them. It also defines record StarSystem with fields starSystemName, starSystemCoordX and starSystemCoordY.

Star name Text starSystemId StarSystemId spectralType SpectralType luminosityClass LuminosityClass deriving Show Read Eq

This works in the same way and defines table star and record Star. New here is column star_system_id that has foreign key constraint linking it to star_system table. Star record has field starStarSystemId (silly name, I know, but that’s how the generated names go), which has type Key StarSystem.

spectral_type and luminosity_class columns in the database are textual (I think VARCHAR), but in the code they’re represented with SpectralType and LuminosityClass data types. In order this to work, we have to define them as normal data types and use derivePersistField that generates extra code needed to store them as text in database:

data SpectralType = O | B | A | F | G | K | M | L | T deriving (Show, Read, Eq) derivePersistField "SpectralType" data LuminosityClass = Iap | Ia | Iab | Ib | II | III | IV | V | VI | VII deriving (Show, Read, Eq) derivePersistField "LuminosityClass"

Final piece in the example is Planet:

Planet name Text position Int starSystemId StarSystemId ownerId FactionId Maybe gravity Double SystemPosition starSystemId position deriving Show Read Eq

This introduces two new things: ownerId FactionId Maybe removes NOT NULL constraint for this column in the database, allowing us to omit storing a value there. It also changes type of planetOwnerId into Maybe (Key Faction). Thus, planet might or might not have an owner, but if it has, database ensures that the link between planet and faction (not shown here) is always valid.

Second new thing is SystemPosition starSystemId position that creates unique index on columns star_system_id and position. Now only one planet can exists on any given position in a star system.

Database isn’t any good, if we can’t insert any data into it. We can do that with a function shown below, that create a solar system with a single planet:

createSolarSystem = do systemId <- insert $ StarSystem "Solar system" 0 0 starId <- insert $ Star "Sol" systemId G V planetId <- insert $ Planet "Terra" 3 systemId Nothing 1.0 return (systemId, starId, planetId)

To use the function, we have to use runDB function that handles the database transaction:

res <- runDB createSolarSystem

There are various ways of loading data from database. For loading a list of them, selectList is used. Here we’re loading all planets that have gravity exactly 1.0 and ordering results by the primary key in ascending order:

planets <- runDB $ selectList [ PlanetGravity ==. 1.0 ] [ Asc PlanetId ]

Loading by primary key is done with get. It returns Maybe, because data might or might be present that match the primary key. Programmer then has to account both cases when handling the result:

planet <- runDB $ get planetId

Updating a specific row is done with update function (updateWhere is for multiple rows):

_ <- runDB $ update planetId [ PlanetName =. "Earth" ]

Finally, sometimes it’s nice to be able to delete the data:

_ <- runDB $ delete planetId _ <- runDB $ deleteWhere [ PlanetGravity >. 2 ]

While persistent is relatively easy to use after you get used to it, it lacks ability to do joins. In such cases one can use library called Esqueleto, that is more powerful and has somewhat more complex API.


Because functions are values in Haskell, nothing prevents storing them in data types:

data Handler = Simple (Int -> Boolean) | Complex (Int -> Int -> Int)

Handler type has two possible values: Simple has a function that turns Int into Boolean (for example odd used to check if given number is odd) and Complex that takes two values of type Int and returns Int (basic arithmetic for example, adding and subtracting).

Hopefully this helps you to follow along as I work on the game.

Easiest way to catch me nowadays is either via email or on fediverse where I’m tuturto@mastodon.social

HPR2757: How to DM

Feb 26, 2019



I've gotten a lot of great feedback on the Interface Zero play-through and the episode about getting started with RPGs I did with Lostnbronx. People have told me that one of the biggest blockers to getting started is knowing what to do as GM.

Now, I've read lots of rulebooks and GM guides, and it seems to me that most of them assume you've either played an RPG before, and so you've seen an example of a Game Master at play, or you've seen one on Youtube or Twitch. It's a safe assumption, but it's easy to forget all of those great examples under pressure. So in this episode, Lostnbronx and I are going to provide you with some clear and direct instructions on what exactly a GM does.

The short version is this:

Tell the players where they are and what they see around them.

Listen to the players when they tell you what they want to do.

Tell the players the outcome, based on your privileged knowledge of the game world or on a roll of the dice, of their actions.

You loop over that sequence, and you're game mastering!

But that makes for a short episode, and anyway, there are details about the process that we can talk about to make you feel more comfortable with the prospect of deciphering a game world with your friends.

To that end, Lostnbronx and I have started a website dedicated to gaming! You should check it out, subscribe to our feed. We discuss everything game-related there, plus a little tech and all manner of topics of interest to geeks.


Right off the bat, it's important to understand that every GM is different. No two styles of running a game match completely, nor should they. And while there's no one correct way to run a game, there are plenty of ways to do it poorly. The GM wears many hats, but in my opinion, the most important job is to make sure that everyone has a good time. Your players are giving you an evening out of their lives. Next week they'll probably give you another. It's your job to make sure that time isn't wasted.

By definition, games, even role-playing games, are a form of entertainment -- like reading a book, watching a movie, or enjoying the circus. When you go to that, the GM is the ringmaster, presenting the show; while the players are both the audience, and the main attraction. The GM controls the world, the people, the monsters, the history, even the weather. The GM controls everything, in fact...except for the player characters. A game master presents the situation, but it's the players who decide what to do with that information.

Now, this is all pretty vague, and describing RPG's is far less informative than playing them. Considering this is a podcast, I encourage you to go back and listen to Klaatu's aforementioned "Interface Zero" episodes. These are excellent examples of actual game play. If you're having a hard time imagining how RPG's are presented and experienced, you'll appreciate those shows.

Now then, almost all games are divided into genre types: sword and sorcery; space opera; spies; super-heroes; and pretty much everything else. And I mean everything! If there's a genre of fiction and storytelling that you enjoy, chances are there's a game or game setting for it somewhere. The most popular style of RPG's out there are fantasy. Think "Lord of the Rings". Think "Harry Potter". Think of anything, in fact, because all of it is possible.

A staple of the high fantasy genre of gaming is the dungeon. Now, that term has two meanings in this sort of game: first, the usual meaning, of what amounts to the basement of a castle, with jails, interrogation rooms, storage rooms, and more. The other meaning refers specifically to a type of adventuring environment. Both of these are usually found underground, but an adventuring dungeon may have nothing to do with any castle. It might be a lost crypt, a cave system, an abandoned gold mine, or the lair of some dreaded beast that's been terrorizing the countryside. In the dungeon might be enemies, monsters, and treasure protected by deadly traps. Magic abounds. There might be puzzles, dark secrets, or a kidnapped prince to rescue.

As a new GM, you can start off any way you want, but in my experience, the best way to get used to how the game works, and how the whole process of providing an evening's entertainment to your friends or family works in this context, is to create a dungeon and run your players through it.

Dungeons generally require set-up time; that is to say, you have to design it in advance. Now, Klaatu and I are currently working on ways to ease that burden, with the ultimate goal of eliminating the pre-work entirely. But for now, let's talk about the traditional way to approach all this. What follows is a step-by-step process, but understand, it's only one of an infinite possible number of them.

STEP 01 -- CREATE THE COUNTRYSIDE Some GM's say creating the world is the first step. Some say creating the godly pantheons of the world is the first. Some say it's the history, or the fantasy races. They're not wrong, but trust me, when you're just starting out, none of that stuff matters. In this example, you'll be running the players through a dungeon. That dungeon is out in the country, within the middle of a large forest.

Now, it will make the beginning and end of the adventure easier if you have a small village nearby where the player characters all live. We'll call it Forestdale for the lack of anything better. In Forestdale, there's an inn or tavern. This is where people get together, tell tall tales, and become inspired to go adventuring, so let's give it a name as well: "The Prancing Unicorn". That's home base. Every player character knows this place, and everyone in it knows them.

One of the stories being swapped at "The Unicorn" lately is about a tribe of dangerous creatures living in an underground lair somewhere within the forest. They are led by an evil wizard, or so the tales go. They have been attacking farmers and merchants who travel through the roads and foot paths of the woods in order to sell their goods in Forestdale. One of the merchants says he saw them travel down the Western path near the Old Bridge. Something must be done, but who would be brave or foolhardy enough to even try?

And that's all you need to create for the world right now. Remember, this stuff is new; no one needs large amounts of detail just yet, least of all you. You'll have enough to juggle.

STEP 02 -- CREATE THE DUNGEON FLOOR PLAN One of the rumors to be heard at "The Prancing Unicorn" is that there's an underground cave system or labyrinth somewhere in the forest. Some say it's a myth, others say their cousin's uncle's sister's best friend came across it once. Either way, its existence is shrouded in mystery, and people are said to go in, but not always come out.

This is your first dungeon. You don't want to do more work than you need to. Let's make this dungeon a single level. Later, you can add a secret panel somewhere that can reveal a set of stairs down to a second level (and from there, a third, fourth, tenth, or more). Right now, it's one level, hidden below the forest. It's dark, it's dangerous. It's plenty.

Putting a dungeon together can be difficult, but it doesn't have to be. The traditional way to create one of these is to use graph or hex paper and draw out the floor map. Each square of the graph paper is equal to ten feet, or, say, three meters. You make note of all rooms, caves, doors, hallways, stairs up or down, floor traps, hidden doors, and anything else you want in there. Be sure to put a set of stone stairs that lead from the forest above, down to this dank and gloomy dungeon.

There are no standard symbols for the different things on the map, despite what anyone might tell you, but for now, let's turn the paper landscape style, and at the top of the page, now held that way, outline one square of the graph paper with a pencil. Inside the square, draw three or four small lines at an angle. This will represent a set of stairs. Next to the stairs, write the letter "U". This is the way to get to the forest above. Granted, it's how the player characters will come down here to begin with, but once they are here, they have to go up to leave, hence the "U". If that's confusing, you can write, "To The Forest Above", next to this square, maybe with a little arrow. You can write anything you want, but this is how the player characters will get in and out of your dungeon.

We're going to draw the floor plan from the top of the page down. The entire dungeon map will be on this one side of the paper. In the corner, draw an arrow pointing up, and put a letter "N" there. That's North. We'll be using compass directions from now on. Granted that when underground, it's hard to get your bearings without a compass, but for this first dungeon, we won't worry about that. North, South, East, West. It makes life easy.

On the bottom of the page, to the South, draw a box in the middle of the page that's ten by ten squares in size. This is where the dungeon tunnels all will be leading, and where we'll have the biggest fight of the adventure. We're setting that up now, so we always know where we're heading. Now go back to the stairs at the top of the page.

Draw a long line from the lower edge of the stairs going West. Stop the line a square or two from the edge of the paper. Now do the same thing going East. Next, move down one square, and draw another line parallel to both of these, going entirely from one side of the page to the other, East to West. You've just created a place for the players to explore, so imagine it for a moment: they come down some broken, forgotten stairs. Let's say they travel at least a hundred feet down, tripping over tree roots and walking through cobwebs, until the stairs deposit them in the middle of a dark tunnel, ten feet wide. It stretches to either side, running East and West out of sight (you know that it goes hundreds of feet in both directions, but you'll let them discover that for themselves). They listen, and can hear nothing but the scurrying of unseen vermin. At least, they hope that's what it is. Not a bad start.

Along this hallway, you'll draw little rectangles, like black bars, on random squares along the Southern side of the tunnel. Not too many, just a few here and there, with generous space in between. These are heavy wooden doors. Some may be locked. That's your choice. If they are, put a little symbol near them. It could be as simple as the letter "L", so let's go with that. Now you know where the all doors are in this particular tunnel, and you know which of them will be a challenge for the player characters to open.

This is just the first tunnel of a larger complex. This complex can be as big or as small as you'd like. Let's say it's moderately sized. Before we draw more tunnels, let's draw the rooms behind those doors. This will tell us how much map space we'll have for further tunnels. Some GM's like to draw all the tunnels first, and then fit in the rooms. You can do it however way you want later on; right now, let's just use this method. Pick a door. Draw a box behind it, three or four squares in size. That's the room. Do the same behind the other doors. Make the rooms different shapes and sizes, but not too big. Let the big room at the bottom be the star. When you're done, you have a huge tunnel, with several mysterious doors, behind which are some good-sized rooms.

On the part of the tunnel that ends on the West side, draw a connecting tunnel South for five squares, and then turn the direction back to the East. Draw this tunnel going that way for ten squares. Put a door or two along here, and draw some rooms for them. Turn the tunnel South again, and go five or six squares, and turn it East again for four squares. Draw a door and room. Maybe it's locked, maybe not. Continue with this meandering, jagged floor plan, wandering East and then West, but always moving South. Add occasional doors and rooms as you go, until your tunnel finally ends on the Western side of the large ten by ten square room at the bottom of the page. Draw a door to get in there.

Now go back up to the long tunnel at the top, and repeat this whole process on the Eastern side, eventually bringing that part of the tunnel to the Eastern edge of the big room at the bottom. Put a door there.

Now, number your rooms on the map, starting at at the top, and working your way down, until you've marked each one. Room numbers are essential, because you'll be keeping track of each one.

The floor plan to your first dungeon is complete. Now you need to put interesting things in it.

STEP 03 -- POPULATE YOUR DUNGEON Okay, on a separate piece of paper, list the rooms of your dungeon. Start at #1, and go down. Beside the room number, you put in a brief description, along with any monsters, treasure, or other points of interest. You'll be consulting this list throughout the game, so write down everything you need to know, in order to minimize the amount of time you'll inevitably have your nose in the rulebook while playing. Monster statistics, including their weapons, and and the damage they do, should all be on this list, though there are ways to simplify the process, once of which I'll go into in a moment.

When putting creatures and things into your dungeon, the first thing to remember is to not overload it. Each room does not need a monster. Not every room needs treasure. It might be helpful to think in terms of what you'd like to see in the dungeon as a whole. Remember the stories of evil creatures, and possibly a wizard, which you heard at "The Dancing Unicorn"? We'll use that as our springboard. This is a starting dungeon, not just for you, but also for the player characters. Starting dungeons mean low-level monsters, so let's go with goblins.

Goblins are generally quite impressed with magic, so we're going to assume a wizard of dubious character has bullied a small tribe of them into being his thugs. They've been waylaying passing merchants and farmers, stealing their wares, and carrying off food (along with the occasional peasant worker, as goblins love the taste of human flesh). Stupid, but dreadful creatures, they have displayed a level of tactical organization that's not normal for them. This, of course, is because the wizard's in charge. Look up the statistics for goblins, and understand what they're like. For this adventure, we're not going to worry about goblin captains, or goblin chiefs, both of which are tougher than your average goblin. No, all the creatures for this adventure have the same statistics. Don't drive yourself crazy writing them down, over and over. Write them once at the bottom of the room description page, and every time the player characters run into a goblin, consult them.

Let's say there are a total of fifteen goblins in this dungeon. They won't all be together; the player characters will encounter a few of them here and there, in various rooms, or maybe ust wandering the tunnels. The rooms themselves will have the spoils of all their raids, including barrels of wine, hams and sides of beef; furs, and a few copper, silver, and gold coins. If there's wine in one of the rooms, maybe the goblins there are drunk, fighting at a penalty to hit and damage. And remember, not all rooms need things in them. Maybe this was once a temple, and there's just broken furniture, and rotting religious robes in some of the rooms. In one, there might also be a tapestry against the wall, depicting a miracle of whatever god this place was once dedicated to. What you might not tell the player characters up front is that the tapestry could fetch a fair amount of gold coins in the market back in Forestdale. Too big to carry while exploring the dungeon, such a thing could always be rolled up and fetched on their way out. Not all treasure is found in wooden chests.

Then again, a lot of it is, so why not put one in the big room to the South? Of course, you have to defeat the evil wizard and his goblin cohorts, wh are hanging out in there. As a rule of thumb, you might want to sprinkle half the goblins throughout the dungeon, leaving the other half here, for the final fight. Stealth matters. Approaching the big room noisily, and kicking open one of the doors, is not stealthy. The player characters might be able to catch the wizard and his minions off-guard, if they move quietly.

In order to be a credible threat to the player characters, this wizard should be of a slightly higher level, say 2nd or 3rd. He'll have some aggressive spells, and he'll have his goblins handy. You'll roll up the wizard the same way the players rolled up their characters, only you'll make him more experienced, and with more spells at his command. Maybe he even has a magic item of some sort. Should the players defeat this guy, this magic item will be part of the treasure; until then, it's something the wizard will use against them. Don't make it too tough. Maybe don't make it tough at all: a +1 Ring of Protection, maybe. Or perhaps, a +1 dagger. That might not sound like much, but it's more than the player character's have when they start.

Not enough excitement, maybe? Just add in a couple of giant rats in one of the rooms. Maybe some large spiders in another. Don't forget to put their statistics down in the room description. Judging how tough or easy a dungeon needs to be comes with experience. My suggestion is to err on the side of toughness, to put more challenges in there than maybe you feel comfortable with. If the player characters are looking depleted and injured, you can say the room is empty, instead of filled with spiders. Also, it doesn't hurt at all to remind the players now and then that it's okay to retreat. They can always come back another day when they're rested, and have made plans based on the knowledge they gained the first time around. It sets up a grudge match...the heroes vs. the evil wizard and his goblin hoard. You, as the GM, just repopulate the goblins, move them around a bit, so they're not all in the same rooms as before (though the big room should still be for the final fight), and //voila//! You've just provided your players with two night's worth of entertainment, for the effort of only one.

And there you have it: a stocked dungeon that dovetails into the local lore of the countryside, ready for your players to explore.

STEP 04 -- ROLLING UP CHARACTERS Some GM's will want a whole night just for this process. Others will just have the players arrive at the game with their characters ready to go, especially if they are experienced with the game. I won't go over the character creation process here, because each game is different, and some are VERY different. I mention this now, though, because the players need characters, and creating them comes before the adventure starts. If the game is as new to them as it is to you, take that whole night to help them create their characters. It's fun all on its own, and it allow's everyone to be familiar with the other characters -- something vital to party survival.

I'm not going to go into detail about the process of rolling up characters, because, like you, Klaatu and I have dedicated an evening just to this process. In a previous episode in this mini-series, the two of us created a character from the ground up, so you can hear what's involved, and how you might want to approach the process with your own players.


If designing your own custom dungeon seems intimidating to you, there is another way. And it's a time-honoured, legitimate way to play, and it's quite often the way I play: you go find an adventure that someone else has already written.

An adventure is the scenario you and your players experience when you sit down at the table to play. It's arguably the *game* (the rulebooks are the game engine, or the mechanics). Wizards of the Coast, Paizo, Catalyst, Kobold Press, Frog God, and many others publish adventures (sometimes called "modules", "scenarios", or "adventure paths") written by professional game designers. Published adventures provide the story framework for your game.

Not all systems publish adventures, though, or you may choose not to use one. If that's the case, spend some time developing a story. Writing a good game is part science, part craft, and part magic, but if you and your players are up to the challenge, then running blindly through a story that's mostly being created spontaneously on the spot can be a lot of fun. If that sounds overwhelming, though, get a published adventure!

Quick tip: Free, small, or introductory adventures are often available from http://drivethrurpg.com, http://dmsguild.com, and https://www.opengamingstore.com

Many adventures have text blocks that provide you with introductory text for each part of the game, they explain clearly what the goal of the players is during that segment, and give you guidance on what players will find in the area and how those discoveries lead to the next plot point.

Broadly speaking, there are two types of published adventures: there are "one-shots" and there are "modules" or "adventure paths".

A one-shot adventure is analogous to a quest in a video game: it's a single, clearly-defined task with a very obvious and immediate result; for example, goblins are terrorizing the hapless citizens of the local village, so go to their cave and clear it out: if you do, you'll relieve the villagers of the horrors, and you get to keep any gold or weapons you find.

The advantage is that it's designed to be a quick, one-time game session, so it's perfect for playing with friends you only see once in a while, or with someone who's never played before and just isn't sure if it's something they want to commit to. Don't be fooled by the page count of these small adventures: it may only be 5 to 10 pages long, sometimes less, but you'll be surprised at how long players can spend exploring a boundless world existing only in their imagination.

Adventure paths or modules or campaigns are bigger stories with loftier goals. You can think of them as lots of little one-shots strung together so that once players accomplish all the tasks and solve all the mysteries over the course of 200 pages, they have a final showdown with some Big Bad, and win themselves a place in the legends of the game world. It's an epic poem instead of a short story. It feels grander, it feels important. The losses along the way are more profound, and the victories sweeter. These campaigns take months to play through and usually expect a gaming group to meet weekly or fortnightly or at least monthtly to work their way through the tale.

I should mention one more kind of book you might stumble across, and those are source books. I mention this because I've had friends go and buy books more or less blindly, and then they bring them back home disappointed that instead of a book of lore about dark elves, they bought an adventure set in the underdark. Or the other way round: they wanted an adventure and ended up with a rule book.

This happens with the bigger systems that produce a lot of media, like {D&D, Shadowrun, Pathfinder, Warhammer}, so get clarity on what you're buying before you make a purchase. If you come across a cool ShadowRun book called RUN FASTER expecting a campaign to run with your friends, you'll be surprised to find that you've purchased a source book full of metatypes, expanded rules, and alternate character creation methods: sort of a Shadowrun Core Rulebook part 2. Same goes for, say, Volo's Guide with D&D, or Ultimate Campaign in Pathfinder. It can be overwhelming and they're not aways labelled clearly (or if they are, the label gets lost in the word cloud of RPG jargon that you're not used to yet), so do a little research first.

I've played through dungeons that a GM created over his lunch break, and I've played through adventures written by clever game designers, and I can confidently say that they're both great ways to RPG. But as a GM, if you feel overwhelmed by the idea of designing a dungeon, a published adventure is a great way to start. Aside from reading a chapter ahead before each game night, all the prep work is done for you, and there's very little thinking required.

Another part of being GM is deciding when a die roll is necessary. Die rolls represent the chance of success or failure when a specific action is taken, but the confusing thing is: if you think hard enough about anything in the world you can find a chance of success or failure. As a GM, it's up to you to decide what's "important" enough for a roll. Strictly speaking, that's determined by the rules. The rules told you what requires a roll, and you're expected to know the rules well enough to make the call.

In practise, however, you have a lot of stuff to track in you head, and remembering what requires a die roll, or deciding to request a die roll even though it may not be strictly required, can feel overwhelming for a new GM.

Good news: Players intuitively know when to roll dice. A player knows their character's skills (because they built the character and wrote it down on their character sheet), so sometimes the actions they choose to take are chosen because it falls within a category of a skill they happen to have. A thief probably wouldn't ever think to *look* for hidden door if the thief were a fighter (who would more likely think to pound on the wall rather than to slyly look for a hidden door). So if your player reaches for dice, let them roll because they're probably right.

I'm sure it's possible to take it too far, but people like to roll dice. It's part of the fun of an RPG, the uncertainty of subjecting yourself to the whims of fate. So when in doubt, either make your players roll dice, or roll dice yourself. I use dice rolls to help me decide everything from NPC reactions to weather conditions. It's usually safe to default to rolling.

Worst case scenario is that die are only picked up for fights and a literal interpretation of skills: and that works because those are the rules as written.


Players drive the story. In video game or movie terminology, they control the "camera". When players are exploring or investigating, let them ask questions or take actions ("I look in the closet"), and answer them as you see fit ("You open the closest and see an array of fine garments.")

"I'll move the clothes aside and examine the walls, and the floor. I'm looking for trap doors or hidden compartments, or anything suspicious."

And so on. Players can choose to investigate and explore for as much as they want. That's the beauty of a pen-and-paper RPG: the world is infinite. That said, you're the GM and you owe it to your players to keep the game moving. You don't to let your players spend 3 real hours searching a room that, in the end, has no bearing upon the plot whatsoever. That can be a delicate matter, because the nature of the game means that you know things that the other players don't, meaning much of the puzzle for players is what they don't know.

Usually I let players explore a space on their own until I feel that they've explored the obvious parts of it, and then I remind them where the exits are, or I remind them how many other rooms there are to explore, or some subtle clue to say, without saying, that they've secured an area.

If players are especially suspicious of something, though, you certainly have the power to generate a subplot, and often times you should do that. It's fun for you and rewarding to players. For instance, if a player is convinced that there's a secret panel in a closet and spends a lot of time investigating, then you might decide that there IS a secret panel in the closet, and then roll on a random table to determine what could possible inside that compartment. Or you could leave the compartment empty, thereby creating a story hook to return to later...what used to be in that compartment? who took it, and why? What were the implications?

Keeping the gaming moving is an inexact, unscientific process, but usually it comes pretty naturally. When you start to get bored of the players exploring, you can bet that they're probably getting bored too, and that's when you know to urge them forward. If all else fails, you can always have something lure them from one space to another: a mysterious sound, an oncoming threat, or a supernatural or divine instinct.

HPR2756: Bash Tips - 20

Feb 25, 2019


Tidying loose ends (Some collateral Bash tips) Deleting arrays

I forgot to cover one thing on my list when doing the last show: I forgot to explain how to delete arrays and array elements. I’ll cover that topic in this episode.

Positional and Special parameters

I have also avoided talking much about the positional and special parameters in Bash: '$1', '$2', '$#' and the rest. I will cover (some of) these in this episode.

Silly titles

I stopped doing the weird episode titles by episode 14 because I thought the joke was getting tired. However, I think a few people missed them (and a certain HPR colleague was found vandalising my new titles as they were being posted ;-), so I have added them inside the notes on the older shows and am adding one here – as a homage to silliness.

Long notes

I have provided detailed notes as usual for this episode, and these can be viewed here.

Links “GNU BASH Reference Manual” Section “3.4 Shell Parameters” Section “4 Shell Builtin Commands” Section “4.1 Bourne Shell Builtins” Section “4.2 Bash Builtin Commands” Section “4.3.1 The Set Builtin”

POSIX Shell Command Language: unset

HPR series: Bash Scripting

Previous episodes under the heading Bash Tips: HPR episode 1648 “Bash parameter manipulation” HPR episode 1843 “Some Bash tips” HPR episode 1884 “Some more Bash tips” HPR episode 1903 “Some further Bash tips” HPR episode 1951 “Some additional Bash tips” HPR episode 2045 “Some other Bash tips” HPR episode 2278 “Some supplementary Bash tips” HPR episode 2293 “More supplementary Bash tips” HPR episode 2639 “Some ancillary Bash tips - 9” HPR episode 2649 “More ancillary Bash tips - 10” HPR episode 2659 “Further ancillary Bash tips - 11” HPR episode 2669 “Additional ancillary Bash tips - 12” HPR episode 2679 “Extra ancillary Bash tips - 13” HPR episode 2689 “Bash Tips - 14 (Some auxiliary Bash tips)” HPR episode 2699 “Bash Tips - 15 (More auxiliary Bash tips)” HPR episode 2709 “Bash Tips - 16 (Further auxiliary Bash tips)” HPR episode 2719 “Bash Tips - 17 (Additional auxiliary Bash tips)” HPR episode 2729 “Bash Tips - 18 (Extra auxiliary Bash tips)” HPR episode 2739 “Bash Tips - 19 (Supplemental auxiliary Bash tips)” Resources: Examples: bash20_ex1.sh, bash20_ex2.sh

HPR2755: My YouTube Subscriptions #2

Feb 22, 2019


I am subscribed to a number of YouTube channels, and I am sharing them with you

Anthony Robustelli - https://www.youtube.com/channel/UCxgAH7EcmKhC9bLm7xQ971g Apple Scruff Radio - https://www.youtube.com/channel/UCGAFIXNYCwA7mJWMY5zFxzw Arthur C Clarke Center for Human Imagination - https://www.youtube.com/channel/UCigIJEygfuAhNEc9kavK2QA Baker Street - https://www.youtube.com/channel/UC8IaZ7-169c2vl3GOehxa6w BBC Earth Unplugged - https://www.youtube.com/channel/UCbwp5B-uDBy-fS4bDA0TEaw Brain Stuff - https://www.youtube.com/channel/UCiefLm_nIz_gOH7XHbgpdCQ Candyrat Records - https://www.youtube.com/channel/UCMJecdKUslHToOEpeuRGwXg Cheryl Brin - https://www.youtube.com/channel/UCtbMXq5siIn3l-u_HKbAmrw Colonial Airstream - https://www.youtube.com/channel/UCaZKKtI5caSI6-WO4zm3VGQ Computerphile - https://www.youtube.com/channel/UC9-y-6csu5WGm29I7JiwpnA Couch’s RV Nation - https://www.youtube.com/channel/UCvAONLxaOn8oc7PS33KN22Q Darren Kitchen - https://www.youtube.com/channel/UCTkpeicFNBuHJCvp4LZEuvw Don Ross - https://www.youtube.com/channel/UCRd5EO6FvhIrqQnk0cscSDA Geeks on Tour - https://www.youtube.com/channel/UCLM_wnCtDaGBWkYGQS4T6Bw Duet Justus - https://www.youtube.com/channel/UCIeTn13FYQI1YL4InzvuWuQ Firesign Theatre - https://www.youtube.com/channel/UCXdhVqpbttKSvBWGWHSBkgw Hana Malhas - https://www.youtube.com/channel/UCpoMVaoVRf3Xvf10_EIZKrg Healthcare Triage - https://www.youtube.com/channel/UCabaQPYxxKepWUsEVQMT4Kw How Stuff Works - https://www.youtube.com/channel/UCa35qyNpnlZ_u8n9qoAZbMQ Jeff Pevar - https://www.youtube.com/channel/UCGd3v3LEwBJOsXkN-RZgFzQ https://www.palain.com/

HPR2754: Craigslist Scam Catch

Feb 21, 2019



Hello and welcome to Hacker Public Radio, I’m Edward Miro and for this episode I decided to record on a personal experience I had recently helping a client catch a Craigslist Scam. This will be part two in my series I’m calling “Information Security for Everyone”. As with most of the content I publish in the world of INFOSEC, my goal is to present the information in a way that a majority of people can get value from and anyone can play this for a friend, colleague or family member and make it easy for the non-hackers in our lives to understand. This particular episode shows a powerful way social-engineering can be implemented to steal money from unsuspecting victims and I will break down a few main points and red flags to look out for at the end.

A couple weeks ago I was sitting with a client when she asked me offhandedly if I’d ever sent a Moneygram before. I told her I had and ask curiously why she wanted to know. She explained that she was very excited to be adopting a puppy from online and she needed to send $350 USD to the service that ships pets across the country. This immediately caused my hacker-sense to start tingling so I probed a bit more about the transaction.

I asked if she had spoken to the seller on the phone, and she said she hadn’t. I said that seemed weird, but she assured me that the seller said it had to do with her religion. I wasn’t aware of any religious prohibitions to speaking on the phone that also allowed using Craigslist, but okay. I told her that that seemed a bit fishy to me. She asserted that she thought it did too at first, but she knew it was legit because she wasn’t sending the money to the seller, it was being sent to a third party pet transportation company that the seller had had contact her. She even showed the website of the company on her cell phone, which to be blunt, to my eyes looked extremely janky. I asked her if we could sit down for a few minutes and take a look at a few details before she sends anyone any money. She reluctantly agreed and really wanted this puppy.

The first thing I asked to look at was the emails back and forth from the seller. I checked Google and all other major social media sites for the sellers name. No matches. Couldn’t Google the sellers email address due to the Craigslist email relay system. This in and of itself might be okay, we all use pseudonyms online sometimes and Craigslist is a site you might not wanna use your real name. Fine.

She then showed me the email thread with the shipping company.

The first strange thing I noticed from the emails was the link to the pet shipping company. The name didn’t match the URL in the link. You’d think a business would be able to get their own name right. I also saw that if you Googled the name given by the shipper, it’s extremely similar to a legitimate pet shipping company and indeed that legit company comes up as the first site found due to Google “fixing” our query. When you go to the link in the email however, the site itself was terrible to my eyes, but not to my client who is not as seasoned as I am at catching scams. I also showed her that the “company” didn’t have any social media presence. At all. No Facebook, Twitter, anything. Also the email address that was contacting her was reallylongcompanyname@outlook.com

She also told me she had spoken to the shippers on the phone and I asked if she still had their number. She did, but she told me she couldn’t ever get through when she called them and they’d always have to call her back. I asked for the number and called it on my phone. It was a Google Voice number! Not only that it was set to screening mode. She also told me when he did call her, he was rude and tried to get her to hurry up and send the money. I told her I was 100% confident this was a scam and I advised her to not go through with the deal.

At this point she was extremely unhappy, but felt it was still a legitimate transaction because she had pictures sent to her of not only the puppy, but of the puppy in the shipping crate at the shipping company waiting for payment to be shipped. She explained that it’s not like it was a person trying to sell dogs or from a puppy mill. It was a lady giving it away for free and the money was for was the shipping. She just didn’t see why a scammer would go to the trouble of doing that and felt the pictures were authentic. I asked her to save all the images to her device and then showed her a site she could use to do reverse image searches. Before she did it, I asked her if she agreed that if this wasn’t a scam those pictures wouldn’t exist anywhere on the internet. She agreed and each of the pictures was found at least 9 other places online. Her heart sank and she didn’t have any further rebuttals to my concerns. She knew it was a scam and I just saved her from losing at least $350 USD. Not to mention that the scammer would have also asked for more money later for “shots” and “insurance”. Who knows how far they might have gotten.

So here are the main red flags:

Seller wouldn’t talk on phone Seller name didn’t seem legitimate Name of shipping company didn’t match URL in email Googling company name shows close match with legitimate company Company website very poorly designed and implemented Company has no social media presence Email address of contact at company using generic email address and not a legit domain Contact at company could only call her and she was never able to make inbound calls Phone number of company was Google Voice number Reverse image searches showed “proof” photos unoriginal

A few of the tricks used by the scammers in this scam to make it more successful:

Listed as adoption versus a sale to alleviate concern Handed off to “second party” to build legitimacy Use cute puppy pictures to appeal to emotion and overrule suspicion Counted on target not paying attention to detail Shipper established a sense of urgency

She was very thankful and I told her to be very careful when anyone from online ever asks her to send money. I told her in all likelihood this was probably one person the whole time, hence why the person adopting out the dog “couldn’t talk on the phone”. They were also probably not even in this country as we know many of these scams aren’t. She did say that the shippers English wasn’t good. I also told her to make she shares this experience with all her friends and family. I always feel the best way to handle someone getting caught in a scam is to be on their side and never shame them. We are all susceptible to scams and social engineering and the best way to proceed is to empower them to share what they’ve learned. I also sent her a link to an article on the BBB site about these very types of scams that I’ll also link below. She was shocked how similar her experience was to the ones explained on the article.

Well, thank you for taking the time to listen to my experience helping a client avoid getting caught in the all too common Craigslist scam. I hope this will help any non-hackers in your life and like I say in all my podcasts, I don’t claim to know all there is to know and love feedback and any opportunities to learn more or collaborate with others in the field. As with most of the research and articles I’ve written in the past, these are geared toward standard users in a business setting and are meant to be a jumping off point for further research and to be a foundation for cyber security 101 level training classes. If you like what I do, and want to have me come speak to your team, or just wanna chat, feel free to email me.

Thank you and have a great day!




HPR2753: Specific Settings In Storytelling

Feb 20, 2019


How does setting interact with plot or character? Why would you choose one type of setting over another? And how do certain specific settings become intrinsic aspects of the story itself?

Lostnbronx takes a breezy, mostly incoherent stab at this rather complicated topic.

HPR2752: XSV for fast CSV manipulations - Part 2

Feb 19, 2019


XSV for fast CSV manipulations - Part 1: Basic Usage



xsv is a command line program for indexing, slicing, analyzing, splitting and joining CSV files. Commands should be simple, fast and composable:

Simple tasks should be easy. Performance trade offs should be exposed in the CLI interface. Composition should not come at the expense of performance.

We will be using the CSV file provided in the documentation.

Commands covered in this episode fixedlengths - Force a CSV file to have same-length records by either padding or truncating them. fmt - Reformat CSV data with different delimiters, record terminators or quoting rules. (Supports ASCII delimited data.) input - Read CSV data with exotic quoting/escaping rules. partition - Partition CSV data based on a column value. split - Split one CSV file into many CSV files of N chunks. sample - Randomly draw rows from CSV data using reservoir sampling (i.e., use memory proportional to the size of the sample). cat - Concatenate CSV files by row or by column.

HPR2751: Battling with English - part 3

Feb 18, 2019


Battling with English - part 3 Some word confusions

In this episode, the third of this series, I’m looking at some words that are sometimes used in the wrong places, often being confused one with another. These words are often particularly difficult to differentiate by people for whom English is not their first language.

Long notes

As usual I have provided detailed notes and examples for this episode, and these can be viewed here.

Links Been: Oxford Dictionaries: Definition of “been” Online Etymology Dictionary: “been” Being: Oxford Dictionaries: Definition of “being” Online Etymology Dictionary: “being” Been versus Being English Practice - Difference between being and been Examples of the use of Being: Example sentences using being Weather: Oxford Dictionaries: Definition of “weather” Online Etymology Dictionary: “weather” Wether: Oxford Dictionaries: Definition of “wether” Online Etymology Dictionary: “wether” Whether: Oxford Dictionaries: Definition of “whether” Online Etymology Dictionary: “whether” Wither: Oxford Dictionaries: Definition of “wither” Online Etymology Dictionary: “wither” Whither: Oxford Dictionaries: Definition of “whither” Online Etymology Dictionary: “whither” Weather, wether, and the rest: Grammarist Grammar Monster Previous episodes in this series: Battling with English - part 1 Battling with English - part 2

HPR2750: Windmill is on the Fritz

Feb 15, 2019


In this episode Ken uses Fritzing tool to keep track of how a winter model village windmill is wired together. Leading to identifying the problem component.

Fritzing is an open-source initiative to develop amateur or hobby CAD software for the design of electronics hardware, to support designers and artists ready to move from experimenting with a prototype to building a more permanent circuit. It was developed at the University of Applied Sciences of Potsdam.
From https://en.wikipedia.org/wiki/Fritzing

HPR2749: Lostnbronx and Klaatu commentary from episode 2743

Feb 14, 2019


Out-takes from episode 2743. This is commentary about modern RPG play style, the character build process, Starfinder as a system, and more.

Did you know that Lostnbronx and Klaatu have a gaming blog? We do! You should go subscribe to it at mixedsignals.ml

The blog features commentary about gaming, tech, geek culture, a podcast or two, and lots more.

HPR2748: Writing Web Game in Haskell - Special events

Feb 13, 2019



I was tasked to write kragii worms in the game and informed that they’re small (10cm / 4 inches) long worms that burrow in ground and are drawn to farming fields and people. They’re dangerous and might eat harvest or people.

Special events build on top of the new system I explained in episode 2733. They are read from same API as regular news and need same ToJSON, FromJSON, ToDto and FromDto instances as regular news (for translating them data transfer objects and then into JSON for sending to client).


Starting from the API interface, the first real difference is when JSON stored into database is turned into NewsArticle. Two cases, where special news have available options added to them and regular news are left unchanged. These options tell player what choices they have when dealing with the situation and evaluated every time special event is loaded, because situation might have changed since special event got stored into database and available options might have changed.

addOptions (key, article) = case article of Special news -> (key, Special $ availableOptions news) _ -> (key, article) availableOptions :: SpecialNews -> SpecialNews availableOptions x = case x of KragiiWorms event _ choice -> KragiiWorms event (eventOptions event) choice

eventOptions is one of the events defined in SpecialEvent type class that specifies two functions every special event has to have. eventOptions lists what options the event has currently available and resolveEvent resolves the event according to choice user might have made (hence Maybe in it).

Type class is parametrized with three types (imaginatively named to a, b and c). First is data type that holds information about special event (where it’s happening and to who for example), second one is one that tells all possible choices player has and third one lists various results that might occur when resolving the event. In this example they’re KragiiWormsEvent, KragiiWormsChoice and KragiiResults.

data KragiiWormsEvent = KragiiWormsEvent { kragiiWormsPlanetId :: Key Planet , kragiiWormsPlanetName :: Text , kragiiWormsSystemId :: Key StarSystem , kragiiWormsSystemName :: Text , kragiiWormsDate :: Int } data KragiiWormsChoice = EvadeWorms | AttackWorms | TameWorms data KragiiResults = WormsStillPresent | WormsRemoved | WormsTamed | CropsDestroyed (RawResource Biological) | FarmersInjured

Definition of the SpecialEvent type class is shown below. Type signature of resolveEvent is gnarly because it’s reading and writing database.

class SpecialEvent a b c | a -> b, a -> c where eventOptions :: a -> [UserOption b] resolveEvent :: ( PersistQueryRead backend, PersistQueryWrite backend , MonadIO m, BaseBackend backend ~ SqlBackend ) => (Key News, a) -> Maybe b -> ReaderT backend m (Maybe EventRemoval, [c])

One more piece we need is UserOption. This records options in a format that is useful in the client side. Each option player has are given title and explanation that are shown on UI.

data UserOption a = UserOption { userOptionTitle :: Text , userOptionExplanation :: [Text] , userOptionChoice :: a }

Current implementation of eventOptions doesn’t allow database access, but I’m planning on adding that at the point where I need it. Example doesn’t show all different options, as they all have same structure. Only first option in the list is shown:

eventOptions _ = [ UserOption { userOptionTitle = "Avoid the worms" , userOptionExplanation = [ "Keep using fields, while avoiding the worms and hope they'll eventually leave." , "50 units of biologicals lost" , "25% chance of worms leaving" ] , userOptionChoice = EvadeWorms } , ... ] Making choice

putApiMessageIdR handles updating news with HTTP PUT messages. First steps is to check that caller has autenticated and retrieve id of their faction. News article that is transferred in body as JSON is parsed and checked for type. Updating regular news articles isn’t supported and is signaled with HTTP 403 status code. One more check to perform is to check that news article being edited actually belong to the faction player is member of. If that’s not the case HTTP 404 message is returned.

If we got this far, news article is updated with the content sent by client (that also contains possible choice made by user). There’s no check that type of news article doesn’t change or that the option selected doesn’t change (I need to add these at later point). In the end, list of all messages is returned back to the client.

putApiMessageIdR :: Key News -> Handler Value putApiMessageIdR mId = do (_, _, fId) <- apiRequireFaction msg <- requireJsonBody let article = fromDto msg _ <- if isSpecialEvent article then do loadedMessages <- runDB $ selectList [ NewsId ==. mId , NewsFactionId ==. fId ] [ Asc NewsDate ] if length loadedMessages == 0 then apiNotFound else runDB $ update mId [ NewsContent =. (toStrict $ encodeToLazyText article) ] else apiForbidden "unsupported article type" loadAllMessages fId Resolving event

Special event occured, user made (or did not) a choice. Now it’s time to simulate what happens. Below is resolveEvent for kragii attack.

resolveEvent keyEventPair (Just choice) = runWriterT . runMaybeT $ case choice of EvadeWorms -> chooseToAvoid keyEventPair AttackWorms -> chooseToAttack keyEventPair TameWorms -> chooseToTame keyEventPair resolveEvent keyEventPair Nothing = runWriterT . runMaybeT $ noChoice keyEventPair

runWriterT and runMaybeT are used as code being called uses monad transformers to add some extra handling. WriterT adds ability to record data (KragiiResult in this case) and MaybeT adds ability to stop computation early if one of the steps return Nothing value.

Let’s walk through what happens when user has chosen to avoid kragii worms and keep working only part of the fields. First step is to load faction information. If faction couldn’t be found, we abort. Next amount of biological matter consumed and how much is left is calculated. Again, if calculation isn’t possible, we’ll abort. This step reaches into database and updates amount of biological matter stored by the faction (again, possibility to stop early). Final step is to check if kragii leave or not (again, chance of abort).

chooseToAvoid :: ( MonadIO m, PersistQueryWrite backend , BaseBackend backend ~ SqlBackend ) => (Key News, KragiiWormsEvent) -> MaybeT (WriterT [KragiiResults] (ReaderT backend m)) EventRemoval chooseToAvoid (_, event) = do faction <- getFaction event (cost, bioLeft) <- calculateNewBio (RawResource 50) (entityVal faction) _ <- destroyCrops faction cost bioLeft removeNews $ PercentileChance 25

Loading faction has several step. Id is stored in the event is used to load planet. Planet might or might have an owner faction, depending on if it has been settled. This faction id is used to load faction data. Loading might fail if corresponding record has been removed from database and planet might not be settled at the given time. Any of these cases will result Nothing be returned and whole event resolution being aborted. I’m starting to really like that I don’t have to write separate if statements to take care of these special cases.

getFaction :: ( MonadIO m, PersistStoreRead backend , BaseBackend backend ~ SqlBackend ) => KragiiWormsEvent -> MaybeT (WriterT [KragiiResults] (ReaderT backend m)) (Entity Faction) getFaction event = MaybeT $ do planet <- lift $ get $ kragiiWormsPlanetId event let owner = join $ fmap planetOwnerId planet res <- lift $ mapM getEntity owner return $ join res

Amount of biological matter in store is stored in faction information. If it’s zero or less, Nothing is returned as there’s nothing to do really. In other cases, amount of biological matter left is calculated and result returned in form of ( cost, biological matter left ). I’m carrying around the cost, as it’s later needed for reporting how much matter was removed.

calculateNewBio :: Monad m => RawResource Biological -> Faction -> MaybeT (WriterT [KragiiResults] m) ((RawResource Biological), (RawResource Biological)) calculateNewBio cost faction = MaybeT $ do let currentBio = factionBiologicals faction return $ if currentBio > 0 then Just $ ( cost , RawResource $ max 0 (currentBio - unRawResource cost)) else Nothing

destroyCrops updates database with new amount of biological matter in store for the faction and records amount of destruction in CropsDestroyed. tell requires that we have Writer at our disposal and makes recording information nice and easy.

destroyCrops :: ( MonadIO m, PersistQueryWrite backend, BaseBackend backend ~ SqlBackend ) => Entity Faction -> RawResource Biological -> RawResource Biological -> MaybeT (WriterT [KragiiResults] (ReaderT backend m)) () destroyCrops faction cost bioLeft = MaybeT $ do _ <- lift $ updateWhere [ FactionId ==. entityKey faction ] [ FactionBiologicals =. unRawResource bioLeft ] tell [ CropsDestroyed cost ] return $ Just ()

Final step is to roll a percentile die against given odds and see what happens. In case of Success, we record that worms were removed and value of function will be Just RemoveOriginalEvent. If we didn’t beat the odds, WormsStillPresent gets recorded and value of function is Just KeepOriginalEvent. Return value will then be used later to mark special event handled.

removeNews :: ( PersistStoreWrite backend, MonadIO m, BaseBackend backend ~ SqlBackend ) => PercentileChance -> MaybeT (WriterT [KragiiResults] (ReaderT backend m)) EventRemoval removeNews odds = MaybeT $ do res <- liftIO $ roll odds case res of Success -> do _ <- tell [ WormsRemoved ] return $ Just RemoveOriginalEvent Failure -> do _ <- tell [ WormsStillPresent ] return $ Just KeepOriginalEvent

So result of this whole matter is:

( [KragiiResults], Maybe EventRemoval )

and whole lot of database activity.

Handling events during simulation

Pieces are now in place, time to put things in motion. When handling special events for a faction, first step is to load all unhandled ones and then call handleSpecialEvent for each of them.

handleFactionEvents :: (BaseBackend backend ~ SqlBackend , PersistStoreWrite backend, PersistQueryRead backend , PersistQueryWrite backend, MonadIO m) => Time -> Entity Faction -> ReaderT backend m [Key News] handleFactionEvents date faction = do loadedMessages <- selectList [ NewsFactionId ==. (entityKey faction) , NewsSpecialEvent ==. UnhandledSpecialEvent ] [ Desc NewsDate ] let specials = mapMaybe extractSpecialNews $ parseNewsEntities loadedMessages mapM (handleSpecialEvent (entityKey faction) date) specials

resolveEvent resolves event based on choice user maybe made (this is what we explored earlier in the episode). Depending on the result of resolveEvent, event gets marked to handled and dismissed. In any case, a news article spelling out what happend is created and saved.

handleSpecialEvent :: (PersistQueryWrite backend, MonadIO m , BaseBackend backend ~ SqlBackend) => Key Faction -> Time -> (Key News, SpecialNews) -> ReaderT backend m (Key News) handleSpecialEvent fId date (nId, (KragiiWorms event _ choice)) = do (removal, results) <- resolveEvent (nId, event) choice _ <- when (removal /= Just KeepOriginalEvent) $ updateWhere [ NewsId ==. nId ] [ NewsSpecialEvent =. HandledSpecialEvent , NewsDismissed =. True ] insert $ report fId date event choice results

Result article creation is abstracted by ResultReport type class. It has single function report that takes parameters: database key of the faction the event concerns of, current time, special event that was processed, choice that was made and list of records telling what happened during resolution. It will return News that is ready to be saved into database.

class ResultsReport a b c | a -> b, a -> c where report :: Key Faction -> Time -> a -> Maybe b -> [c] -> News quite long and verbose instance essentially take event, choice and results and build a string explaining what actually happened <> is monoid operation for combining things, here used for text

Instance declaration is pretty long, because there’s many different cases to account for and by definition they’re all pretty verbose. I have included it in its entirity below, as it might be interesting to glance over and see different kinds of combinations that resolution might create.

instance ResultsReport KragiiWormsEvent KragiiWormsChoice KragiiResults where report fId date event choice results = let content = KragiiNews { kragiiNewsPlanetId = kragiiWormsPlanetId event , kragiiNewsPlanetName = kragiiWormsPlanetName event , kragiiNewsSystemId = kragiiWormsSystemId event , kragiiNewsSystemName = kragiiWormsSystemName event , kragiiNewsExplanation = repText , kragiiNewsDate = timeCurrentTime date } in mkNews fId date $ KragiiResolution content where repText = header choice <> " " <> removed choice (WormsRemoved `elem` results) <> " " <> injury <> " " <> destruction <> " " header (Just EvadeWorms) = "Local farmers had chosen to work on their fields, while avoiding the kragii worms." header (Just AttackWorms) = "Local farmers had decided to attack the worms with chemicals and burning." header (Just TameWorms) = "Decision to try and tame the kragii had been taken." header Nothing = "No decision what to do about worms had been taken." removed (Just EvadeWorms) True = "After some time, there has been no new kragii sightings and it seems that the threat is now over." removed (Just AttackWorms) True = "Attacks seem to have worked and there has been no new kragii sightings." removed (Just TameWorms) True = "Kragii has been tamed and put into use of improving soil quality." removed Nothing True = "Despite farmers doing nothing at all about the situation, kragii worms disappeared eventually." removed (Just EvadeWorms) False = "Kragii are still present on the planet and hamper farming operations considerability." removed (Just AttackWorms) False = "Despite the best efforts of farmers, kragii threat is still present." removed (Just TameWorms) False = "Taming of the worms was much harder than anticipated and they remain wild." removed Nothing False = "While farmers were debating best course of action, kragii reigned free and destroyed crops." injury = if FarmersInjured `elem` results then "Some of the personnel involved in the event were seriously injured." else "There are no known reports of personnel injuries." totalDestroyed = mconcat $ map (x -> case x of CropsDestroyed n -> n _ -> mempty) results destruction = if totalDestroyed > RawResource 0 then "In the end, " <> pack (show (unRawResource totalDestroyed)) <> " units of harvest was destroyed." else "Despite of all this, no harvest was destroyed."

While there are still pieces left tha