scriptreplay in javascript

categories: code

TL;DR: http://mister-muffin.de/scriptreplay/

Using terminal applications instead of GUI applications has the definitive speed advantage of not having to spend some time on moving a cursor to a 2D coordinate on the screen but instead just doing a 2mm downward motion with one or two fingers. I wonder if something other than terminal applications will allow me to interact with my computer faster until the invention of direct neural interfaces.

I really like terminal applications - not only because of the speed advantage but also because they offer much more real-estate in terms of usable screen space as they dont waste space on stuff like buttons, menu bars or all those pixels wasted on separators and the space between UI elements. Starting to use the pentadactyl firefox extension was not only a huge browsing speed improvement for me but I could also finally use my whole frickin 1920x1080 pixels for viewing the website (well except for a 19 pixels status bar at the bottom).

Now lets finally come to the topic of this post: scriptreplay in javascript.

script(1) and scriptreplay(1), being part of the bsdutils package in debian/ubuntu and the util-linux package in rpm based distribution will probably also already be installed on your system and is one of those really handy tools you did not know of before even though they were always there.

script is a program that you can use to capture a terminal session or console application output whereas scriptreplay is able to replay that session by using a timing file that script is able to output on stderr. Without the timings file, the typescript will include all terminal interaction and is readily readable with a text editor or printable or easily uploadable to a pastebin (no more selecting parts of your terminal window with your mouse and copy-pasting that into the browser). Without the timing file it is useful to document a process - for example if you want to show others how a bug happened on your system or for a homework submission you have to hand in.

A very powerful feature is the mentioned timingfile you can capture by redirecting the stderr output of script into a file. With the use of scriptreplay you can then watch your terminal interaction in real time.

While it would be kinda tedious to share your typescript and timingfile over a pastebin so that a party would have to download those manually and use scriptreplay to watch them, I imagined a kind of youtube for terminal sessions. This would also solve the problem of all those youtube videos that are screen captures of terminal windows - needlessly encoding text as moving images and by that not only destroying the ability to copy&paste things but also needlessly increasing the filesize.

I remembered having seen such a website years ago but dont manage to find it again. To show a proof of concept I prepared the following website:

http://mister-muffin.de/scriptreplay/

I will probably never have the time to make a real webservice out of it but maybe something of this is useful for others.

View Comments

minimal qemu-binfmt root with multistrap

categories: code

In this earlier post I listed the following manual method to fill /etc/qemu-binfmt/arm/ with shared libraries of the foreign architecture:

wget http://ftp.debian.org/debian/pool/main/e/eglibc/libc6_2.11.2-11_armel.deb
sudo mkdir -p /etc/qemu-binfmt/arm/
sudo dpkg -x libc6_2.11.2-11_armel.deb /etc/qemu-binfmt/arm/
rm libc6_2.11.2-11_armel.deb

This approach has two disadvantages. Firstly when some other library is required one again has to manually look up the url to the latest deb of the package that contains it and manually extract it to the target directory. Secondly, whenever one wants to upgrade the libraries because of incompatibilities, one has to repeat the whole process. The downloading is hard to script because version numbers and thus, urls to packages change. Fortunately apt can be used to to automatically get the latest binary packages for any architecture and suite. This is the same mechanism that multistrap uses to setup a rootfs. Without further thinking I hacked together a small script that basically does, was the core of what multistrap does:

#!/bin/sh -ex

usage() {
echo "Usage: $0 arch suite rootdir [mirror]" }

MIRROR="http://127.0.0.1:3142/ftp.de.debian.org/debian"

[ "$#" -ne 3 ] && [ "$#" -ne 4 ] && { usage; exit; }

ARCH="$1"
SUITE="$2"
ROOTDIR="$3"
MIRROR=${4:-$MIRROR}

[ -e "$ROOTDIR" ] && { echo "root directory still exists"; exit; }

mkdir "$ROOTDIR"

ROOTDIR=`realpath "$ROOTDIR"`

# apt options
APT_OPTS="-y"
APT_OPTS=$APT_OPTS" -o Apt::Architecture=$ARCH"
APT_OPTS=$APT_OPTS" -o Dir::Etc::TrustedParts=$ROOTDIR/etc/apt/trusted.gpg.d"
APT_OPTS=$APT_OPTS" -o Dir::Etc::Trusted=$ROOTDIR/etc/apt/trusted.gpg"
APT_OPTS=$APT_OPTS" -o Apt::Get::AllowUnauthenticated=true"
APT_OPTS=$APT_OPTS" -o Apt::Get::Download-Only=true"
APT_OPTS=$APT_OPTS" -o Apt::Install-Recommends=false"
APT_OPTS=$APT_OPTS" -o Dir=$ROOTDIR/"
APT_OPTS=$APT_OPTS" -o Dir::Etc=$ROOTDIR/etc/apt/"
APT_OPTS=$APT_OPTS" -o Dir::Etc::SourceList=$ROOTDIR/etc/apt/sources.list"
APT_OPTS=$APT_OPTS" -o Dir::State=$ROOTDIR/var/lib/apt/"
APT_OPTS=$APT_OPTS" -o Dir::State::Status=$ROOTDIR/var/lib/dpkg/status"
APT_OPTS=$APT_OPTS" -o Dir::Cache=$ROOTDIR/var/cache/apt/"

# initial setup for apt and dpkg to work properly
mkdir -p $ROOTDIR
mkdir -p $ROOTDIR/etc/apt/
mkdir -p $ROOTDIR/etc/apt/sources.list.d/
mkdir -p $ROOTDIR/etc/apt/preferences.d/
mkdir -p $ROOTDIR/var/lib/apt/
mkdir -p $ROOTDIR/var/lib/apt/lists/partial/
mkdir -p $ROOTDIR/var/lib/dpkg/
mkdir -p $ROOTDIR/var/cache/apt/
touch $ROOTDIR/var/lib/dpkg/status

# fill sources.list
echo deb $MIRROR $SUITE main > $ROOTDIR/etc/apt/sources.list

# update and install git and ruby
apt-get $APT_OPTS update
apt-get $APT_OPTS install libc6 libselinux1 libacl1 man-db libstdc++6

# unpack downloaded archives
for deb in $ROOTDIR/var/cache/apt/archives/*.deb; do
dpkg -x $deb $ROOTDIR
done

# cleanup
rm -rf $ROOTDIR/var/lib/apt/lists
rm -rf $ROOTDIR/var/cache/apt/

One would invoke it like that:

./create-binfmt-tree.sh armel sid binfmt-root

I did something like that before (documented here) so it seemed straight forward to do it like that. It was only after I was done and everything was working when I realized that multistrap has the omitrequired option with which one can do exactly what I wanted: not build a whole rootfs but just get some packages with apt and extract them to a directory. This is the much simpler multistrap config that does the same as the script above:

[General]
arch=
directory=
cleanup=true
unpack=true
noauth=true
aptsources=Debian
bootstrap=Debian
allowrecommends=false
addimportant=false
omitrequired=true

[Debian]
packages=libc6 libselinux1 libacl1 man-db libstdc++6
source=http://ftp.de.debian.org/debian
suite=sid
omitdebsrc=true

Invoking it like that will produce a rootfs I can put into /etc/qemu-binfmt/arm right away:

multistrap -a armel -d binfmt-root -f multistrap-binfmt.conf
View Comments

new toy

categories: blog

Finally my new toy arrived: Seagate FreeAgent GoFlex Net

seagate goflex net

  • 1.2 GHz Marvell Kirkwood 88F6281
  • 128MB RAM
  • 256MB NAND
  • 1x GbEthernet
  • 1x USB 2.0
  • 2x SATA
  • 2.3 W power consumption

I acquired it for 40 EUR which is quite a bargain for a computer with these specs.

I already found the pin headers for RX and TX so hacking it can start right after I got myself a new serial usb adapter.

In the photo above, there is a 10-pin header. In the upper row, the three pins from the left are GND, TX and RX. With screen I can then use:

screen /dev/ttyUSB0 115200
View Comments

latex with blogofile

categories: blog

I can now finally add latex formulas to this blog :)

I am using this filter.

To test, have some maxwell:

\begin{aligned}
\nabla \cdot \mathbf{D} &= \rho_f \\
\nabla \cdot \mathbf{B} &= 0 \\
\nabla \times \mathbf{E} &= -\frac{\partial \mathbf{B}} {\partial t} \\
\nabla \times \mathbf{H} &= \mathbf{J}_f + \frac{\partial \mathbf{D}} {\partial t} \\
\end{aligned}
View Comments

generate silent wav

categories: code

I wanted a few seconds of complete silent audio. Since I already knew how audio is encoded using LPCM I thought it would be simple enough to write a small snippet that also creates the RIFF file structure around it for a complete *.wav file. And indeed it is. This is how to generate a *.wav file containing some seconds of silence.

#!/usr/bin/python

from struct import pack
from sys import stdout

duration = 1 # seconds of silence
channels = 1 # number of channels
bps = 16 # bits per sample
sample = 44100 # sample rate
ExtraParamSize = 0
Subchunk1Size = 16+2+ExtraParamSize
Subchunk2Size = duration*sample*channels*bps/8
ChunkSize = 4 + (8 + Subchunk1Size) + (8 + Subchunk2Size)

stdout.write("".join([
'RIFF', # ChunkID (magic) # 0x00
pack('<I', ChunkSize), # ChunkSize # 0x04
'WAVE', # Format # 0x08
'fmt ', # Subchunk1ID # 0x0c
pack('<I', Subchunk1Size), # Subchunk1Size # 0x10
pack('<H', 1), # AudioFormat (1=PCM) # 0x14
pack('<H', channels), # NumChannels # 0x16
pack('<I', sample), # SampleRate # 0x18
pack('<I', bps/8 * channels * sample), # ByteRate # 0x1c
pack('<H', bps/8 * channels), # BlockAlign # 0x20
pack('<H', bps), # BitsPerSample # 0x22
pack('<H', ExtraParamSize), # ExtraParamSize # 0x22
'data', # Subchunk2ID # 0x24
pack('<I', Subchunk2Size), # Subchunk2Size # 0x28
'\0'*Subchunk2Size
]))

And because it was fun, the whole thing in shell:

#!/bin/sh

pack_int(){ printf "%08X\n" $1 | sed 's/\([0-9A-F]\{2\}\)\([0-9A-F]\{2\}\)\([0-9A-F]\{2\}\)\([0-9A-F]\{2\}\)/\\\\\\x\4\\\\\\x\3\\\\\\x\2\\\\\\x\1/I' | xargs printf; }

pack_short(){ printf "%04X\n" $1 | sed 's/\([0-9A-F]\{2\}\)\([0-9A-F]\{2\}\)/\\\\\\x\2\\\\\\x\1/I' | xargs printf; }

duration=1
channels=1
bps=16
sample=44100
Subchunk1Size=18
Subchunk2Size=$(($duration*$sample*$channels*$bps/8))
ChunkSize=$((20 + $Subchunk1Size + $Subchunk2Size))

echo -n RIFF
pack_int $ChunkSize
echo -n "WAVEfmt "
pack_int $Subchunk1Size
pack_short 1
pack_short $channels
pack_int $sample
pack_int $((bps/8 * channels * sample))
pack_short $((bps/8 * channels))
pack_short $bps
pack_short 0
echo -n data
pack_int $Subchunk2Size

dd if=/dev/zero bs=1 count=$Subchunk2Size 2>/dev/null
View Comments
« Older Entries -- Newer Entries »