summaryrefslogtreecommitdiffstats
path: root/util/bin
diff options
context:
space:
mode:
Diffstat (limited to 'util/bin')
-rwxr-xr-xutil/bin/TouchpadToggle8
-rwxr-xr-xutil/bin/anonbox.net57
-rwxr-xr-xutil/bin/dic78
-rwxr-xr-xutil/bin/galileo3
-rwxr-xr-xutil/bin/google.suggest8
-rwxr-xr-xutil/bin/graphitec5
-rwxr-xr-xutil/bin/hrefs20
-rwxr-xr-xutil/bin/krebdate10
-rwxr-xr-xutil/bin/lgoinstall131
-rwxr-xr-xutil/bin/magic63
-rwxr-xr-xutil/bin/make-data-url7
-rwxr-xr-xutil/bin/make-realwallpaper258
-rwxr-xr-xutil/bin/mobile.vvs.de167
-rwxr-xr-xutil/bin/my-global-ipv4-addr52
-rwxr-xr-xutil/bin/naturalvoices.att18
-rwxr-xr-xutil/bin/nextpath12
-rwxr-xr-xutil/bin/randline2
-rwxr-xr-xutil/bin/sshkill33
-rwxr-xr-xutil/bin/statsc4
-rwxr-xr-xutil/bin/timer14
-rwxr-xr-xutil/bin/translate.google44
-rwxr-xr-xutil/bin/untouch8
-rwxr-xr-xutil/bin/uriparse28
-rwxr-xr-xutil/bin/vvs.de61
-rwxr-xr-xutil/bin/wiki.firstpar23
-rwxr-xr-xutil/bin/wikipedia5
-rwxr-xr-xutil/bin/with6
27 files changed, 1125 insertions, 0 deletions
diff --git a/util/bin/TouchpadToggle b/util/bin/TouchpadToggle
new file mode 100755
index 00000000..17fd46b8
--- /dev/null
+++ b/util/bin/TouchpadToggle
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+#This script toggles the touchpad on a netbook using synclient.
+
+status=`synclient|awk '/TouchpadOff/{printf$3}'`
+status=`expr \( $status + 1 \) \% 2`
+synclient TouchpadOff=$status
+
diff --git a/util/bin/anonbox.net b/util/bin/anonbox.net
new file mode 100755
index 00000000..3b648afb
--- /dev/null
+++ b/util/bin/anonbox.net
@@ -0,0 +1,57 @@
+#! /bin/bash
+#### anonbox.net [--check]
+#### anonbox account creator
+set -euf
+
+##
+script_begin_date="`date --rfc-3339=ns`"
+
+##
+GET() {
+ wget --quiet --no-check-certificate -O- https://anonbox.net/en/
+}
+
+## retrieve data
+eval "$(${GET-GET} |
+ sed -n '
+s^<dd><p>\([[:alnum:]@.]\+\)</p></dd>$\
+ email="\1" ; p
+s^<dd><p><a href="\([^"\\]\+\)">.*</a></p></dd>$\
+ uri="\1/" ; p
+s^<dd><p>\([0-9]\+\)/\([0-9]\+\)/\([0-9]\+\) \([0-9]\+\):\([0-9]\+\) \([ap]\).m.</p></dd>$\
+ Y=20\3 ; \
+ m=\1 ; \
+ d=\2 ; \
+ H=\4 ; \
+ M=\5 ; \
+ p=\6 ; p')"
+
+## make best-before-date RFC-3339-(seconds)-conform
+case "$p" in
+ p) H="`echo $H+12 | bc`" ;;
+esac
+s=00
+z=+02:00
+best_before="$Y-$m-$d $H:$M$z"
+
+##
+script_end_date="`date --rfc-3339=ns`"
+
+##
+for key in email uri best_before script_begin_date script_end_date ; do
+ eval "val=\"\$$key\""
+ echo "$key=\"$val\""
+done
+
+##
+if echo "$*" | tr "$IFS" ' ' | egrep -q "(^| )--check( |$)"; then
+ file="/tmp/save-$email"
+ echo "file=\"$file\""
+ echo >&2
+ echo "# downloading email..." >&2
+ while ! curl -ksS "$uri" | tee "$file" | grep .; do
+ sleep 10
+ done
+fi
+
+#### end of file.
diff --git a/util/bin/dic b/util/bin/dic
new file mode 100755
index 00000000..b3dac847
--- /dev/null
+++ b/util/bin/dic
@@ -0,0 +1,78 @@
+#! /bin/sh
+# usage: dic WORD [LANG]
+# where LANG may be one of en, fr, es, it, ch, ru, pt, pl
+# multiple WORDs may be seperated by + like this: multiple+words
+set -euf
+
+main() {
+
+ case $# in
+ 1|2) :;; # ok
+ *) usage; exit 23;;
+ esac
+
+ # all three are used by GET
+ search="$1"
+ langlang="${2-en}de"
+ lang="de"
+
+ GET | simplify | tac
+}
+
+GET() {
+ curl -sS -b 'LEOABTEST=T; browser=webkit%3B5%3Bajax' \
+ "https://dict.leo.org/dictQuery/m-vocab/$langlang/query.xml?tolerMode=nof&lp=$langlang&lang=$lang&rmWords=off&rmSearch=on&search=$search&searchLoc=0&resultOrder=basic&multiwordShowSingle=on"
+}
+
+simplify() {
+ sed '
+ s|<repr>|\nREPR: |g
+ s|</repr>|\n|g
+ ' | grep ^REPR |
+ sed '
+ s/^REPR: //
+ 1~2{s/$//}
+ 2~2{s/$//}
+ ' |
+ tr -d \\n |
+ sed '
+ s// - /g
+ s//\n/g
+
+ #q
+
+ s/&#8660;/⇔/g
+ s/&#160;/ /g; # &nbsp;
+ s/ */ /g
+
+ # <!-- undefined_translation: en:pl_ext -->
+ s/ *<!--[^>]*-->//g
+
+ s|<i> *|/|g
+ s| *</i>|/|g
+
+ s:<sup>1</sup>:¹:g; s:<sup>2</sup>:²:g; s:<sup>3</sup>:³:g;
+ s:<sup>:^(:g
+ s:</sup>:):g
+
+ s:<sub>0</sub>:₀:g;
+ s:<sub>1</sub>:₁:g; s:<sub>2</sub>:₂:g; s:<sub>3</sub>:₃:g;
+ s:<sub>4</sub>:₄:g; s:<sub>5</sub>:₅:g; s:<sub>6</sub>:₆:g;
+ s:<sub>7</sub>:₇:g; s:<sub>8</sub>:₈:g; s:<sub>9</sub>:₉:g;
+ s:<sub>:_(:g
+ s:</sub>:):g
+
+ s:<b> *::g
+ s: *</b>::g
+
+ s|<small> *||g
+ s| *</small>||g
+
+ '
+}
+
+usage() {
+ sed -rn '/^# usage:/,/^[^#]/{/^#/{s/# //;p}}' "$0" >&2
+}
+
+main "$@"
diff --git a/util/bin/galileo b/util/bin/galileo
new file mode 100755
index 00000000..854f1302
--- /dev/null
+++ b/util/bin/galileo
@@ -0,0 +1,3 @@
+#!/bin/sh
+export voice=klara
+./wiki.firstpar http://de.m.wikipedia.org/wiki/::Random | xargs ./naturalvoices.att
diff --git a/util/bin/google.suggest b/util/bin/google.suggest
new file mode 100755
index 00000000..9bde17dc
--- /dev/null
+++ b/util/bin/google.suggest
@@ -0,0 +1,8 @@
+#! /bin/sh
+
+uri="http://google.com/complete/search?output=json&q=$*"
+
+curl -sS "$uri" | sed -n '
+ s:^window.google.ac.h(\|)$::gp
+'
+echo
diff --git a/util/bin/graphitec b/util/bin/graphitec
new file mode 100755
index 00000000..52aa9834
--- /dev/null
+++ b/util/bin/graphitec
@@ -0,0 +1,5 @@
+#!/bin/sh
+H=${GRAPHITE_HOST:-localhost}
+P=${GRAPHITE_PORT:-2003}
+curr=$(date '+%s')
+printf "%s %s %s\n" $1 $2 $curr | nc -q0 $H $P
diff --git a/util/bin/hrefs b/util/bin/hrefs
new file mode 100755
index 00000000..3a1a51de
--- /dev/null
+++ b/util/bin/hrefs
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+_hrefs() {
+ sed -n 's/href="\([^"]\+\)"/\n&\n/gp' |
+ sed -n 's/^href="\([^"]\+\)"$/\1/p'; }
+
+_add_prefix_to_relative_hrefs() {
+ sed '/^http:/!s^'"$1"''; }
+
+_main() {
+ case $# in
+ (0) _hrefs;;
+ (1) _hrefs | _add_prefix_to_relative_hrefs "$1";;
+ (*)
+ echo "bad command line: $0 $*" >&2; exit 23;;
+ esac; }
+
+set -euf
+_main "$@"
+#### end of file.
diff --git a/util/bin/krebdate b/util/bin/krebdate
new file mode 100755
index 00000000..b2aa02d2
--- /dev/null
+++ b/util/bin/krebdate
@@ -0,0 +1,10 @@
+#! /bin/sh
+set -euf
+
+if test "${nosudo-false}" != true -a `id -u` != 0; then
+ echo "we're going sudo..." >&2
+ exec sudo "$0" "$@"
+ exit 23 # go to hell
+fi
+
+date --date="`ssh krebs 'date --rfc-3339=s'`"
diff --git a/util/bin/lgoinstall b/util/bin/lgoinstall
new file mode 100755
index 00000000..37ce6e16
--- /dev/null
+++ b/util/bin/lgoinstall
@@ -0,0 +1,131 @@
+#! /bin/sh
+#
+# usage: lgoinstall [path [OPTIONS...]]
+#
+# This script tries to goinstall ${OPTIONS...} local/$(basename $path)
+#
+# path defaults to $PWD
+#
+# target=local/$(basename $path)
+# ensure there's a symlink local/$target somewhere in $GOROOT or $GOPATH
+# goinstall $target
+#
+# TODO use the same argument order as goinstall
+#
+set -euf
+
+#fqtarget="$(readlink -f "$PWD")"
+fqtarget="$(cd "${1-$PWD}" && echo "$PWD")"
+target="local/$(basename "$fqtarget")"
+
+#
+# resolve PATH [relpath [FS]] # ====> abspath...
+#
+# Resolve relpath to abspath for each component x separated by FS in PATH
+# where x/relpath is an existing file.
+#
+# relpath defaults to ""
+# FS defaults to ":"
+#
+# Example:
+#
+# resolve "/bin:/usr/bin" sh # ====> /bin/sh
+#
+resolve() {
+ set -- "$1" "${2+/$2}" "${3-:}" "$IFS"
+ IFS="$3"
+ for i in $1; do
+ ! test -x "$i$2" || echo "$i$2"
+ done
+ unset i
+ IFS="$3"
+}
+
+#
+# xargstest TEST_ARGS...
+#
+# Read filenames from stdin and
+# write each filename that satisfies test # $TEST_ARGS to stdout.
+#
+# Each %x in TEST_ARGS gets replaced by the readlink -f of the filename.
+#
+# Example:
+#
+# xargstest -d %x <<EOF
+# /bin/sh
+# /usr
+# EOF
+# # ====> /usr
+#
+xargstest() {
+ while read x; do
+ fqx="$(readlink -f "$x")"
+ if sub %x "$x" sub %fqx "$fqx" test "$@"; then
+ #if test "${@//%x/$fqx}"; then
+ echo "$x"
+ fi
+ done | grep .
+}
+
+sub() {
+ sub1="$1"
+ sub2="$2"
+ shift 2
+ set -- "${@//$sub1/$sub2}"
+ unset sub1 sub2
+ "$@"
+}
+
+path="${GOROOT-}${GOPATH+:$GOPATH}"
+
+#
+# if there's a src/$target that points to $fqtarget, then succeed
+#
+if x="`resolve "$path" src/$target | xargstest "$fqtarget" = %fqx`"
+then
+ echo "good $target: $x -> $fqtarget" >&2
+ shift # off $1 = $fqtarget
+ echo goinstall "$@" "$target" >&2
+ exec goinstall "$@" "$target"
+fi
+
+#
+# if there's some other src/$target then die
+#
+if x="`resolve "$path" src/$target | xargstest ! -x %x -o "$fqtarget" != %fqx`"
+then
+ echo bad $target: $x >&2
+ echo check your GOROOT and/or GOPATH or eliminate that $target >&2
+ exit 23
+fi
+
+#
+# if we've no Go-source in $fqtarget then die to prevent clobbering $GOPATH.
+#
+if ! ls | grep '\.go$'; then
+ echo "$1 seems to contain no Go-source... abort." >&2
+ exit 23
+fi
+
+#
+# if we can write to some src/local then symlink $PWD and retry
+#
+if x="`resolve "$path" src/local | xargstest -w %x`"
+then
+ #echo writable src/local: $x
+ ln -vsnf $fqtarget $x
+ exec "$0" "$@"
+fi
+
+#
+# if we can write to some src then mkdir src/local and retry
+#
+if x="`resolve "$path" src | xargstest -w %x`"
+then
+ #echo writable src: $x
+ mkdir "$x/local"
+ exec "$0" "$@"
+fi
+
+echo "This script failed: good luck, you're on your own!" >&2
+exit 23
diff --git a/util/bin/magic b/util/bin/magic
new file mode 100755
index 00000000..a404c0c3
--- /dev/null
+++ b/util/bin/magic
@@ -0,0 +1,63 @@
+#! /bin/sh
+set -euf
+
+bs="# begin krebs magic <$2>"
+es="# end krebs magic <$2>"
+
+has() {
+ grep -q "^$bs$" $3 && grep -q "^$es$" $3
+}
+
+create() {
+ destroy "$@"
+ cat>>$3<<EOF
+$bs
+`cat`
+$es
+EOF
+}
+
+retrieve() {
+ sed -n "/^$bs$/,/^$es$/p" $3 | sed '1d;$d'
+}
+
+update() {
+ ! has "$@" || create "$@"
+}
+
+destroy() {
+ if has "$@"; then
+ cache="`cat $3`"
+ echo "$cache" | sed "/^$bs$/,/^$es$/d" >$3
+ fi
+}
+help() {
+cat <<EOF
+Usage: $0 FUNCTION DELIMITER_NAME FILE
+$0 creates,updates or destroys magic inside a file.
+It can be used to reliably add or remove custom lines.
+For example add own lines in /etc/rc.local to auto-load
+scripts.
+
+FUNCTION:
+ create -- creates new magic in file, takes stdin as content in magic
+ update -- updates already existing magic with text from stdin
+ destroy -- destroys magic boundary
+ retrieve -- retrieve the content of magic and writes to stdout
+
+Not yet implemented is the handling of magic not starting with the
+shell comment symbol "#".
+
+EOF
+
+}
+case $1 in
+ (create) create "$@" ;;
+ (retrieve) retrieve "$@" ;;
+ (update) update "$@" ;;
+ (destroy) destroy "$@" ;;
+ (*)
+ help >&2
+ echo 'Error 1: You are made of stupid!' >&2
+ exit 23
+esac
diff --git a/util/bin/make-data-url b/util/bin/make-data-url
new file mode 100755
index 00000000..a9d014e6
--- /dev/null
+++ b/util/bin/make-data-url
@@ -0,0 +1,7 @@
+#! /bin/sh
+set -euf
+for path; do
+ type="`file -bi "$path"`"
+ data="`base64 -w 0 "$path"`"
+ echo "data:$type;base64,$data"
+done
diff --git a/util/bin/make-realwallpaper b/util/bin/make-realwallpaper
new file mode 100755
index 00000000..ba2c6853
--- /dev/null
+++ b/util/bin/make-realwallpaper
@@ -0,0 +1,258 @@
+#!/bin/sh
+set -euf
+
+###### USAGE #####
+#run in new directory(will be polluted with images
+#just run ./make-realwallpaper
+
+main() {
+ # fetch source images in parallel
+ #fetch nightmap-old-raw.jpg \
+ # http://awka.sourceforge.net/Night_le_huge.jpg &
+ fetch nightmap-raw.jpg \
+ http://www.zeitnews.org/sites/default/files/users/20/article_slideshow_images/nasa-noaa-satellite-reveals-new-views-earth-night-1354814354_0.jpg &
+ fetch daymap-raw.png \
+ http://www.nnvl.noaa.gov/images/globaldata/SnowIceCover_Daily.png &
+ fetch clouds-raw.jpg \
+ http://user.chol.com/~winxplanet/cloud_data/clouds_2048.jpg &
+ fetch krebs.sat.tle \
+ http://www.celestrak.com/NORAD/elements/stations.txt &
+ wait
+
+ #check_type nightmap-old-raw.jpg image
+ check_type nightmap-raw.jpg image
+ check_type daymap-raw.png image
+ check_type clouds-raw.jpg image
+
+ in_size=2048x1024
+ xplanet_out_size=1466x1200
+ out_geometry=1366x768+100+160
+
+ nightsnow_color='#0c1a49' # nightmap
+ #nightsnow_color='#0a3b5c' # nightmap-old
+
+ # normalize *-raw.* to *.png
+ #nightmap-old-raw.jpg
+ for raw in \
+ nightmap-raw.jpg \
+ daymap-raw.png \
+ clouds-raw.jpg \
+ ;
+ do
+ normal=${raw%-raw.*}.png
+ if needs_rebuild $normal $raw; then
+ echo "make $normal; normalize $raw" >&2
+ convert $raw -scale $in_size $normal
+ fi
+ done
+
+ # create nightmap-fullsnow
+ if needs_rebuild nightmap-fullsnow.png; then
+ convert -size $in_size xc:$nightsnow_color nightmap-fullsnow.png
+ fi
+
+ # extract daymap-snowmask from daymap-final
+ if needs_rebuild daymap-snowmask.png daymap.png; then
+ convert daymap.png -threshold 95% daymap-snowmask.png
+ fi
+
+ # extract nightmap-lightmask from nightmap
+ if needs_rebuild nightmap-lightmask.png nightmap.png; then
+ convert nightmap.png -threshold 25% nightmap-lightmask.png
+ fi
+
+ # create layers
+ make_layer nightmap-snowlayer.png nightmap-fullsnow.png daymap-snowmask.png
+ make_layer nightmap-lightlayer.png nightmap.png nightmap-lightmask.png
+
+ # apply layers
+ flatten nightmap-lightsnowlayer.png \
+ nightmap-lightlayer.png \
+ nightmap-snowlayer.png
+
+ flatten nightmap-final.png \
+ nightmap-lightsnowlayer.png \
+ nightmap.png
+ # nightmap-old.png
+
+ # make all unmodified files as final
+ for normal in \
+ daymap.png \
+ clouds.png \
+ ;
+ do
+ final=${normal%.png}-final.png
+ needs_rebuild $final &&
+ ln $normal $final
+ done
+
+ make_gcloud_cloudmask
+
+ map=daymap-final.png
+ night_map=nightmap-final.png
+ cloud_map=gcloud-cloudmask.png
+ satellite_file=krebs.sat
+
+ # create xplanet output
+ cat >xplanet.config <<EOF
+[earth]
+"Earth"
+map=$map
+night_map=$night_map
+cloud_map=$cloud_map
+cloud_threshold=10
+shade=15
+EOF
+
+ # create xplanet output satellite version
+ cat >xplanet-sat.config <<EOF
+[earth]
+"Earth"
+map=$map
+night_map=$night_map
+cloud_map=$cloud_map
+cloud_threshold=10
+satellite_file=$satellite_file
+shade=15
+EOF
+
+ if needs_rebuild krebs.sat; then
+ cat >krebs.sat <<EOF
+25544 "ISS" Image=none trail={orbit,-2,2,1} color=grey thickness=1 fontsize=10
+37820 "T1" Image=none trail={orbit,-2,2,1} color=grey thickness=1 fontsize=10
+39175 "ATV-4" Image=none trail={orbit,-2,2,1} color=grey thickness=1 fontsize=10
+39258 "CYG" Image=none trail={orbit,-2,2,1} color=grey thickness=1 fontsize=10
+EOF
+ fi
+
+ if needs_rebuild krebs.mar; then
+ cat >krebs.mar <<EOF
+EOF
+ fi
+
+ # rebuild every time to update shadow
+ xplanet --num_times 1 --geometry $xplanet_out_size \
+ --output xplanet-output.png --projection merc -config xplanet.config
+
+ # rebuild everytime satellite version
+ xplanet --num_times 1 --geometry $xplanet_out_size \
+ --output xplanet-sat-output.png --projection merc -config xplanet-sat.config
+
+ # trim xplanet output
+ if needs_rebuild realwallpaper.png xplanet-output.png; then
+ convert xplanet-output.png -crop $out_geometry realwallpaper.png
+ fi
+
+ # trim xplanet-sat output
+ if needs_rebuild realwallpaper-sat.png xplanet-sat-output.png; then
+ convert xplanet-sat-output.png -crop $out_geometry realwallpaper-sat.png
+ fi
+}
+
+# generate clouds from google maps
+make_gcloud_cloudmask() {
+ echo 'fetch gcloud-*.png tiles' >&2
+ for y in $(seq -w 0 15); do
+ for x in $(seq -w 0 15); do
+ echo "curl -sS -o gcloud-$y-$x.png -z gcloud-$y-$x.png \\\"https://mts0.google.com/vt/lyrs=h@239000000,weather_nolabels,weather_0cloud&hl=en&src=app&x=$x&y=$y&z=4&s=Galil\\\""
+ done
+ done | xargs --max-args=1 -P 10 -I @ sh -c @
+ gcloud_tiles=$(find -name 'gcloud-[0-9][0-9]-[0-9][0-9].png'|sort)
+ if needs_rebuild gcloud-raw.png $gcloud_tiles; then
+ echo 'make gcloud-raw.png' &&
+ montage -mode Concatenate -background None \
+ $gcloud_tiles -tile x16 gcloud-raw.png
+ fi
+
+ check_type gcloud-raw.png image
+
+ gcloud_in_size=2048x2048
+ gcloud_out_size=2048x1024
+ gcloud_out_geometry=2048x1024+0+512
+ gcloud_base_color='#ffffff'
+
+ if needs_rebuild gcloud-normal.png gcloud-raw.png; then
+ echo "make gcloud-normal.png; normalize gcloud-raw.png" >&2
+ convert -flatten gcloud-raw.png \
+ -scale $gcloud_in_size gcloud-normal.png
+ fi
+
+ if needs_rebuild gcloud-distmap.png; then
+ convert -size 2048x2048 gradient: -rotate 180 \
+ -fx "p{i, (asinh(tan((j/h+0.5)*pi))/2.6+0.5) * h }" \
+ gcloud-distmap.png
+ fi
+
+ if needs_rebuild gcloud-cloudmask.png gcloud-normal.png; then
+ echo 'make gcloud-cloudmask.png' &&
+ convert gcloud-normal.png gcloud-distmap \
+ -fx 'p{i,v*h}' \
+ -crop $gcloud_out_geometry \
+ gcloud-cloudmask.png
+ fi
+
+ if needs_rebuild gcloud-fullcloud.png; then
+ echo 'make gcloud-fullcloud.png' &&
+ convert -size $gcloud_out_size xc:$gcloud_base_color gcloud-fullcloud.png
+ fi
+}
+
+# usage: getimg FILENAME URL
+fetch() {
+ echo "fetch $1"
+ curl -sS -z "$1" -o "$1" "$2"
+}
+
+# usage: check_type FILENAME TYPE
+check_type() {
+ if ! file -ib "$1" | grep -q "^$2/"; then
+ echo "$1 is not of type $2" >&2
+ rm "$1"
+ return 1
+ fi
+}
+
+# usage: image_size FILENAME
+image_size() {
+ identify "$1" | awk '{print$3}'
+}
+
+# usage: make_mask DST SRC MASK
+make_layer() {
+ if needs_rebuild "$@"; then
+ echo "make $1 (apply mask)" >&2
+ convert "$2" "$3" -alpha off -compose copy_opacity -composite "$1"
+ fi
+}
+
+# usage: flatten DST HILAYER LOLAYER
+flatten() {
+ if needs_rebuild "$@"; then
+ echo "make $1 (flatten)" >&2
+ composite "$2" "$3" "$1"
+ fi
+}
+
+# usage: needs_rebuild DST SRC...
+needs_rebuild() {
+ a="$1"
+ shift
+ if ! test -e "$a"; then
+ #echo " $a does not exist" >&2
+ result=0
+ else
+ result=1
+ for b; do
+ if test "$b" -nt "$a"; then
+ #echo " $b is newer than $a" >&2
+ result=0
+ fi
+ done
+ fi
+ #case $result in
+ # 0) echo "$a needs rebuild" >&2;;
+ #esac
+ return $result
+}
+
+main "$@"
diff --git a/util/bin/mobile.vvs.de b/util/bin/mobile.vvs.de
new file mode 100755
index 00000000..fdc4cca2
--- /dev/null
+++ b/util/bin/mobile.vvs.de
@@ -0,0 +1,167 @@
+#! /bin/sh
+#
+# NAME
+# mobile.vvs.de - web scraper for VVS departure information
+#
+# SYNOPSIS
+# mobile.vvs.de ORIGIN [HH [MM [YYmmdd]]]
+#
+# DESCRIPTION
+# The mobile.vvs.de utility fetches departure information from the
+# Internet and prints the results to standard output.
+#
+# OPERANDS
+# ORIGIN The point of departure.
+#
+# HH, MM, YYmmdd
+# The time and date of departure. Defaults to the current
+# time and date.
+#
+# STDIN
+# Not used.
+#
+# INPUT FILES
+# None.
+#
+# ENVIRONMENT VARIABLES
+# The following environment variables affect the execution of mobile.vvs.de:
+#
+# limit Limits the number of entries to be fetched.
+#
+# origin, H, M, Ymd
+# Provide defaults operands. If origin is set, then ORIGIN
+# becomes optional. The order of the operands doesn't change
+# by these variables. These variables are overridden by the
+# operands.
+#
+# ASYNCHRONOUS EVENTS
+# Defaults.
+#
+# STDOUT
+# The first line has the format:
+#
+# "\e[4m%s:%s %s\e[m\n", H, M, origin_real_name
+#
+# where H and M are the corresponding provided or default operands.
+# origin_real_name is the real name of the point of departure.
+#
+# The subsequent lines specify the departing means of transport.
+# Each line has the format:
+#
+# "%s %s → %s\n", time_of_departure, line_number, destination
+#
+# where time_of_departure is self-evident, and line_number and
+# destination identify the route and direction.
+#
+# STDERR
+# Not used.
+#
+# OUTPUT FILES
+# None.
+#
+# EXTENDED DESCRIPTION
+# None.
+#
+# EXIT STATUS
+# 0 A departure board could be fetched.
+#
+# 1 ORIGIN doesn't specify an acceptable point of departure.
+#
+# EXAMPLES
+# 1. Get the top three current departures at Stuttgart, Hauptbahnhof:
+#
+# $ limit=3 mobile.vvs.de hauptbahnhof
+#
+# FUTURE DIRECTIONS
+# None.
+#
+# BUGS
+# The format of STDOUT suffers from bit rot.
+#
+# SEE ALSO
+# vvs.de
+#
+# COPYRIGHT
+# All departure information is copyrighted by Verkehrs- und
+# Tarifverbund Stuttgart GmbH. The original copyright statement can
+# be obtained online at http://www.vvs.de/impressum .
+#
+# The following code is your fault.
+#
+set -euf
+
+ltrim() {
+ sed "s/^[${1-$symbols}]*//"
+}
+
+POST() {
+ ## TODO url-encode, trim
+ tr '\n' '&' | sed 's/&$//' |
+ w3m -config /dev/null -cols 256 -post /dev/stdin -dump "${1-$URI}"
+}
+
+limit=${limit-10}
+origin="${1-$origin}"
+H="${2-${H-`date +%H`}}"
+M="${3-${M-`date +%M`}}"
+Ymd="${4-${Ymd-`date +%Y%m%d`}}"
+
+URI='http://mobil.vvs.de/mobile/XSLT_DM_REQUEST'
+
+echo "
+sessionID=0
+requestID=0
+language=de
+locationServerActive=1
+useRealtime=1
+anySigWhenPerfectNoOtherMatches=1
+limit=$limit
+deleteAssignedStops_dm=1
+mode=direct
+convertCrossingsITKernel2LocationServer=1
+convertStopsPTKernel2LocationServer=1
+convertAddressesITKernel2LocationServer=1
+convertPOIsITKernel2LocationServer=1
+itdLPxx_dest=
+useAllStops=1
+maxAssignedStops=1
+itOptionsActive=1
+trITMOTvalue100=5
+ptOptionsActive=1
+useProxFootSearch=0
+w_regPrefAm=1
+w_objPrefAl=2
+w_objPrefAl=12
+itdLPxx_script=true
+place_dm=
+placeState_dm=empty
+nameState_dm=empty
+nameInfo_dm=invalid
+typeInfo_dm=invalid
+placeInfo_dm=invalid
+reducedAnyWithoutAddressObjFilter_dm=103
+reducedAnyPostcodeObjFilter_dm=64
+reducedAnyTooManyObjFilter_dm=2
+anyObjFilter_dm=126
+type_dm=any
+name_dm=$origin
+itdTimeHour=`echo $H | ltrim 0`
+itdTimeMinute=`echo $M | ltrim 0`
+itdDate=$Ymd
+" | POST "$URI" | sed -rn '
+ s/^Von:[^[:alpha:]]+(.*)$/'$H:$M' \1/p
+ /Haltestelle/,/^ *$/{
+ /Haltestelle|^ *$/!{
+ s/[[:space:]]*\[info\][[:space:]]*$//
+ p
+ }
+ }
+' | {
+ read REPLY
+ echo "$REPLY"
+ while read time dev no dest ; do
+ printf "$time %3s → %s\n" $no "$dest"
+ done
+}
+
+####
diff --git a/util/bin/my-global-ipv4-addr b/util/bin/my-global-ipv4-addr
new file mode 100755
index 00000000..71608a8a
--- /dev/null
+++ b/util/bin/my-global-ipv4-addr
@@ -0,0 +1,52 @@
+#! /bin/sh
+#
+# usage: my-global-ipv4-addr [URL]
+#
+# if URL is provided then fetch and parse it for IPv4 addrs
+# else try all known urls
+#
+if test $# = 1; then
+ has() { type "$1" 1>/dev/null 2>/dev/null; }
+ parse() {
+ sed -n 's/.*\(\(1\?[0-9][0-9]\|2[0-5][0-9]\)\.\(1\?[0-9][0-9]\|2[0-5][0-9]\)\.\(1\?[0-9][0-9]\|2[0-5][0-9]\)\.\(1\?[0-9][0-9]\|2[0-5][0-9]\)\).*/\1/p' |
+ grep .
+ }
+ get () {
+ # TODO get random valid user agent
+ if has curl; then
+ curl -m 1 -A Mozilla -sS "$1" 2>/dev/null
+ elif has wget; then
+ wget -T 1 -U Mozilla -O "$1" 2>/dev/null
+ else
+ echo 'Error 1: You are made of stupid!' >&2
+ exit 23
+ fi
+ }
+
+ #addrs="`get "$1" | parse`"
+ #echo "$1:" $addrs >&2
+ #echo "$addrs"
+ get "$1" | parse
+else
+
+ vote() {
+ sort | uniq -c | sort -r -n
+ }
+ winner() {
+ head -n 1 | awk '{print$2}'
+ }
+
+ grep -v ^# |
+ sed -n '1,$p' |
+ xargs -P 42 -n 1 "$0" | vote | winner
+fi<<EOF
+checkip.dyndns.com
+www.whatismyip.de
+www.eigene-ip.de
+whatismyip.org
+www.ipaddressworld.com
+http://ip-check.info/?lang=de
+http://www.ip-adress.com/what_is_my_ip/
+http://www.spyber.com/
+http://www.ipchicken.com/
+EOF
diff --git a/util/bin/naturalvoices.att b/util/bin/naturalvoices.att
new file mode 100755
index 00000000..ea893fc0
--- /dev/null
+++ b/util/bin/naturalvoices.att
@@ -0,0 +1,18 @@
+#!/bin/sh
+cd $(dirname $(readlink -f $0))
+
+. ../lib/naturalvoices/att.sh
+
+: ${1?please provide \$1 as text}
+
+text=$(echo $* | sed 's/ /+/g')
+voice="${voice:-reiner}"
+
+OUTFILE="`mktemp /tmp/voice.XXXXXXXX`"
+trap "rm $OUTFILE" TERM INT EXIT
+
+get_tts "$text"
+
+play_file "$OUTFILE"
+
+
diff --git a/util/bin/nextpath b/util/bin/nextpath
new file mode 100755
index 00000000..fbffa894
--- /dev/null
+++ b/util/bin/nextpath
@@ -0,0 +1,12 @@
+#! /bin/sh
+#
+# nextpath [component...]
+#
+# echo $PATH with the components stripped
+#
+set -euf
+
+pattern="^\\(${1-}$(shift;for i; do echo -n "\\|$i"; done)\\)$"
+
+echo -n "$(echo -n "$PATH" | tr : '\n' | grep -v "$pattern")" | tr '\n' :
+echo
diff --git a/util/bin/randline b/util/bin/randline
new file mode 100755
index 00000000..df36b344
--- /dev/null
+++ b/util/bin/randline
@@ -0,0 +1,2 @@
+#! /bin/sh
+cat | shuf | head -n 1
diff --git a/util/bin/sshkill b/util/bin/sshkill
new file mode 100755
index 00000000..80300483
--- /dev/null
+++ b/util/bin/sshkill
@@ -0,0 +1,33 @@
+#! /bin/sh
+#