Ordered these around 2013/07. As expected you can get better/cheaper stuff today.

The Lian Li PCQ-25b was the main thing I wanted, it is a mini itx case with no stupid CD ROM bay that will hold like 8(?) drives. It was hard to find a mini itx motherboard at the time with lots of SATA ports on it. But easier now i'm sure.

I stuck a crappy old power supply in it that I had left over, so that's not included. If you spend extra and get a "gold" or "platinum" instead of "bronze" its efficiency is greater (which lowers the amount of power it will use, especially when the components draw less.)

The CPU i used back then was 32nm sandy bridge; they have 22nm ivy bridge now, which are more power-efficient i think.

# A meager re-implementation of debian's run-parts in shell script, for
# platforms that lack a working one (e.g. Centos 5).
# Copyright 2013 Michael F. Lamb <>
# License: GPLv3

From the AGPL v3, Section 13: [emphasis mine]

If you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network ... an opportunity to receive the Corresponding Source of your version ...

Q. GPLv3 ensures my software remains free by requiring anyone who conveys a copy to also provide source code, regardless of whether they are distributing verbatim or modified copies.

AGPLv3 has a similar effect for software that is intended to be hosted as a service. However, its clause requiring source code to be provided to network users (section 13) states that the requirement only applies if the party hosting my software has modified it. If they host my software unmodified, they escape the obligation to provide source code to their users. Why?

A. Because placing conditions on the modification of software is the only available mechanism in copyright law it can use to achieve that goal.


Let's set up a shared directory!

$ mkdir shared; chgrp users shared/; chmod g+s shared/
$ ls -lF
total 4
drwxrwsr-x 2 datagrok users 4096 Jan  9 04:37 shared/

Looks good. Let's try it out:

$ touch shared/foo.txt
class UnknownValueDefaultsToKey(dict):
def __getitem__(self, key):
return self.get(key, key)
foox = UnknownValueDefaultsToKey({
'a': 100,
'b': 200,
'c': 300,

PulseAudio tricks

Record both mic and headphones

By default, if you're using Mumble, Teamspeak, etc., and you use a separate piece of software to record the meeting, you'll get audio for either yourself or your remotes, but not both.

This simple method causes microphone input to be fed into the sound output. So, this will only work when:

  1. you are using headphones and
  2. you don't mind hearing your own voice in your headphones when you speak.
View Makefile
# Base dirs
SRC_DIR = src
TMP_DIR = tmp
DEV_DIR = dev
# Copyright 2015 Michael F. Lamb
# License: AGPLv3+
# Uses heading data in the document to generate a nested unordered list with links to the headings.
# Assumes headings already have ids set.
# Requires jQuery.
buildTOCLinks = (os) ->
return if os?.length == 0
View ackermann.asm
#!/usr/bin/spim -file
# ackermann.asm
# (c) 2015 Michael F. Lamb <>
# License: AGPLv3+
# A naive implementation of the two-argument Ackermann function:
# / n+1 if m = 0,
# A(m,n) = { A(m-1, 1) if m>0 and n=0,