From 3c3894593e94776825542cd016f2bb2b75036fbd Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Thu, 6 Dec 2012 19:37:29 -0500 Subject: [PATCH] Import the scripts directory from my website. --- HEADER.txt | 4 + WTFPL-2 | 14 +++ c-is-not-cxx.c | 79 +++++++++++++++ clean-modules.zsh | 46 +++++++++ cmdwrap.c | 120 +++++++++++++++++++++++ dpicalc.c | 66 +++++++++++++ fetchmail-sync.zsh | 28 ++++++ fucked.scheme | 2 + genlibs.sh | 28 ++++++ get_extension.zsh | 46 +++++++++ gitcvs.zsh | 144 +++++++++++++++++++++++++++ ircmpc.pl | 134 +++++++++++++++++++++++++ libs.sh | 63 ++++++++++++ maildir-clean.zsh | 60 ++++++++++++ modules.zsh | 64 ++++++++++++ mpdbetter.sed | 52 ++++++++++ mpdscripts.sh | 239 +++++++++++++++++++++++++++++++++++++++++++++ mplus-t-gen.py | 38 +++++++ musicstats.zsh | 61 ++++++++++++ openexec.c | 164 +++++++++++++++++++++++++++++++ polya.tex | 72 ++++++++++++++ quine.hs | 2 + quine.sed | 28 ++++++ replaygain.zsh | 64 ++++++++++++ runcron.zsh | 24 +++++ spamassassin.zsh | 29 ++++++ 26 files changed, 1671 insertions(+) create mode 100644 HEADER.txt create mode 100644 WTFPL-2 create mode 100644 c-is-not-cxx.c create mode 100755 clean-modules.zsh create mode 100644 cmdwrap.c create mode 100644 dpicalc.c create mode 100755 fetchmail-sync.zsh create mode 100644 fucked.scheme create mode 100755 genlibs.sh create mode 100755 get_extension.zsh create mode 100755 gitcvs.zsh create mode 100644 ircmpc.pl create mode 100755 libs.sh create mode 100755 maildir-clean.zsh create mode 100755 modules.zsh create mode 100755 mpdbetter.sed create mode 100755 mpdscripts.sh create mode 100755 mplus-t-gen.py create mode 100755 musicstats.zsh create mode 100644 openexec.c create mode 100644 polya.tex create mode 100644 quine.hs create mode 100755 quine.sed create mode 100755 replaygain.zsh create mode 100755 runcron.zsh create mode 100755 spamassassin.zsh diff --git a/HEADER.txt b/HEADER.txt new file mode 100644 index 0000000..870ffdf --- /dev/null +++ b/HEADER.txt @@ -0,0 +1,4 @@ +Various short programs. Generally, they are described in comments at the top +of the source file. Most of these programs are free to be copied, modified +and/or distributed under the terms of the Do What The Fuck You Want To Public +License, version 2. There is NO WARRANTY, to the extent permitted by law. diff --git a/WTFPL-2 b/WTFPL-2 new file mode 100644 index 0000000..cb33446 --- /dev/null +++ b/WTFPL-2 @@ -0,0 +1,14 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + 22 rue de Plaisance, 75014 Paris, France + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + diff --git a/c-is-not-cxx.c b/c-is-not-cxx.c new file mode 100644 index 0000000..a942b82 --- /dev/null +++ b/c-is-not-cxx.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2008-2010 Nick Bowler + * + * License WTFPL2: Do What The Fuck You Want To Public License, version 2. + * This is free software: you are free to do what the fuck you want to. + * There is NO WARRANTY, to the extent permitted by law. + * + * This is, to the best of my knowledge, a strictly conforming ANSI C + * (C89) program which is not a C++ program. This proves by counter- + * example that C++ is not a superset of C. + * + * Some of the "techniques" used in this file are stupid legacy features. + * Please don't take this as an example of a well-written C program. + * + * The output of this program should be: + * The old answer was 42, but the new answer is 54. + * + * There are more than 10 different things wrong with this program if you + * consider it as C++. Can you spot them all? This is not valid C99 for + * a few of these reasons. For now, it is pointless to update this to + * C99 -- there are just too many obvious incompatibilities. + */ + +#include +#include + +#define and 42 +#define or 54 + +static struct baz { + struct foo { + enum { + ANSWER1 = and, + ANSWER2 = or, + ANSWER3 = -ANSWER1 + } val; + } foo; +}; + +const int foo; +typedef int baz(); +baz main; + +int main(argc, argv) + int argc; + char **argv; +{ + struct foo foo = { 0 }; + int *new; + + if (argc >= foo.val) { + return main(bar(), argv); + } + + goto assign; + { + int old = 0; + assign: + old = -argc; + + new = malloc(sizeof 'x'); + if (!new) { + perror("malloc"); + return EXIT_FAILURE; + } + + *new = ANSWER2; + printf("The old answer was %d, but the new answer is %d.\n", + old, *new); + free(new); + } + + return 0; +} + +bar() +{ + return (enum{X = ANSWER3})-X//**/-1 + ; +} diff --git a/clean-modules.zsh b/clean-modules.zsh new file mode 100755 index 0000000..4ea8251 --- /dev/null +++ b/clean-modules.zsh @@ -0,0 +1,46 @@ +#!/usr/bin/env zsh +# +# Copyright © 2012 Nick Bowler +# +# Prunes directories in /lib/modules that do not correspond to any kernel +# version in /boot. If the -f option is not specified, only print out what +# will be removed. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +force=no +verbose=no +while getopts 'fv' opt $@; do + case $opt in + f) force=yes ;; + v) verbose=yes ;; + \?) exit 1 ;; + esac +done + +[[ force = yes ]] || verbose=yes + +boot=/boot +kernbase=$boot/vmlinuz- +kernels=($kernbase*(N)) + +if ! [[ $#kernels -ge 1 ]]; then + printf '%s: no kernels found in %s, aborting\n' "$0" "$boot" + exit 1 +fi + +typeset -A kernmap +for v in ${${kernels%.old}#$kernbase}; do + kernmap[$v]=false +done + +modbase=/lib/modules +for d in $modbase/*; do + v=${d#$modbase/} + if $kernmap[$v] :; then + [[ $verbose = yes ]] && printf '%s\n' "$d" + [[ $force = yes ]] && rm -rf "$d" + fi +done diff --git a/cmdwrap.c b/cmdwrap.c new file mode 100644 index 0000000..f146c8b --- /dev/null +++ b/cmdwrap.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2010 Nick Bowler + * + * License WTFPL2: Do What The Fuck You Want To Public License, version 2. + * This is free software: you are free to do what the fuck you want to. + * There is NO WARRANTY, to the extent permitted by law. + * + * Putting . in PATH is generally not a good idea, for a variety of reasons. + * However, some programs expect it to be there, and do not function correctly + * without it. This program allows one to invoke specific programs in the + * current working directory as though . was in the PATH without it actually + * being there. + * + * To work, place a copy of (or symlink to) this program somewhere that is + * actually in the PATH. The name of the command determines what program + * gets invoked. Basic checks are done to avoid accidental infinite + * recursion. + * + * This is probably not portable to non-GNU/Linux systems. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include +#include + +/* Common shell return codes */ +#define SHELL_CMD_NOT_FOUND 127 +#define SHELL_CMD_NOT_EXEC 126 + +/* + * A wrapper around readlink which dynamically allocates a buffer large + * enough to contain the entire filename. Also add a null terminator + * so that the filename can be used as a C string. + */ +char *readlink_alloc(const char *path) +{ + ssize_t bufsize = 64, rc; + char *buf = NULL, *tmp; + + while (1) { + if (bufsize >= SSIZE_MAX/2) { + fprintf(stderr, "cmdwrap: %s: %s\n", + path, strerror(ENAMETOOLONG)); + break; + } + + tmp = realloc(buf, bufsize * 2); + if (!tmp) { + fprintf(stderr, "cmdwrap: %s\n", strerror(errno)); + break; + } + + bufsize *= 2; + buf = tmp; + + rc = readlink(path, buf, bufsize); + if (rc == -1) { + fprintf(stderr, "cmdwrap: %s: %s\n", + path, strerror(errno)); + break; + } else if (rc < bufsize) { + buf[rc] = 0; + return buf; + } + } + + free(buf); + return NULL; +} + +int main(int argc, char **argv) +{ + char *curexe, *newexe, fdname[64]; + int fd; + + if (argc < 1) { + fprintf(stderr, "cmdwrap: command name must be present in the argument list.\n"); + return SHELL_CMD_NOT_FOUND; + } + + fd = open(argv[0], O_RDONLY); + if (fd == -1) { + fprintf(stderr, "cmdwrap: %s: %s\n", argv[0], strerror(errno)); + return SHELL_CMD_NOT_FOUND; + } + + /* Try to avoid accidental infinite recursion. */ + sprintf(fdname, "/proc/self/fd/%d", fd); + newexe = readlink_alloc(fdname); + if (!newexe) + return SHELL_CMD_NOT_FOUND; + + curexe = readlink_alloc("/proc/self/exe"); + if (!curexe) + return SHELL_CMD_NOT_FOUND; + + if (strcmp(newexe, curexe) == 0) { + fprintf(stderr, "cmdwrap: infinite recursion detected\n"); + return SHELL_CMD_NOT_EXEC; + } + + /* + * Some programs expect argv[0] to point to their actual executable + * (potentially after a path lookup). But if we leave argv[0] as it + * is, they'll tend to find this program instead of the right one. + * + * Fix that up, too. + */ + argv[0] = newexe; + free(curexe); + + fexecve(fd, argv, environ); + fprintf(stderr, "cmdwrap: %s: %s\n", argv[0], strerror(errno)); + return SHELL_CMD_NOT_EXEC; +} diff --git a/dpicalc.c b/dpicalc.c new file mode 100644 index 0000000..42b4d18 --- /dev/null +++ b/dpicalc.c @@ -0,0 +1,66 @@ +/* + * Copyright © 2011 Nick Bowler + * + * License WTFPL2: Do What The Fuck You Want To Public License, version 2. + * This is free software: you are free to do what the fuck you want to. + * There is NO WARRANTY, to the extent permitted by law. + */ + +#include +#include +#include +#include +#include + +const char *progname = "dpicalc"; + +static unsigned long +simple_strtoul(const char *str, const char *name, int base) +{ + unsigned long ret; + char *end; + + errno = 0; + ret = strtoul(str, &end, base); + if (errno != 0) { + fprintf(stderr, "%s: %s: invalid %s: %s\n", + progname, str, name, strerror(errno)); + exit(EXIT_FAILURE); + } else if (*end != '\0') { + fprintf(stderr, "%s: %s: invalid %s: trailing garbage\n", + progname, str, name); + exit(EXIT_FAILURE); + } + + return ret; +} + +int main(int argc, char **argv) +{ + double diagonal, ratio, phys_width; + unsigned long w, h; + + if (argc > 0) + progname = argv[0]; + + if (argc < 4) { + fprintf(stderr, "usage: %s diagonal pixel_w pixel_h\n", + progname); + return EXIT_FAILURE; + } + + diagonal = strtod(argv[1], NULL); + w = simple_strtoul(argv[2], "pixel width", 10); + h = simple_strtoul(argv[3], "pixel height", 10); + + ratio = (double) h / w; + if (!isnormal(ratio)) { + fprintf(stderr, "%s: nonsensical aspect ratio (%.2f)\n", + progname, ratio); + } + + phys_width = sqrt(diagonal*diagonal / (1 + ratio*ratio)); + printf("%.1f\n", w / phys_width); + + return 0; +} diff --git a/fetchmail-sync.zsh b/fetchmail-sync.zsh new file mode 100755 index 0000000..45a4e01 --- /dev/null +++ b/fetchmail-sync.zsh @@ -0,0 +1,28 @@ +#!/usr/bin/env zsh +# +# Copyright (C) 2010 Nick Bowler +# +# Simple script which ensures that a running fetchmail daemon is +# sleeping, by forcing a fetch run and waiting until it finishes. +# This is useful for log rotation: the fetchmail daemon will not +# write to the log file while it is sleeping. It is also useful +# for manually invoking fetch runs. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +setopt nonotify + +pid=`head -n 1 ~/.fetchmail.pid 2>/dev/null` + +if ! [[ $pid > 0 && $(ps --no-heading $pid) =~ fetchmail ]]; then + echo "$0: fetchmail is not running." + exit 1 +fi + +coproc sed --unbuffered '/^fetchmail: sleeping/q' +tail -s 0.1 -n 0 -f ~/.fetchmaillog --pid $! >&p & +kill -USR1 $pid +<&p +wait diff --git a/fucked.scheme b/fucked.scheme new file mode 100644 index 0000000..5f3235b --- /dev/null +++ b/fucked.scheme @@ -0,0 +1,2 @@ +(define fucked (lambda (x) (display "fucked\n") (x x))) +(fucked (call-with-current-continuation (lambda (k) (k k)))) diff --git a/genlibs.sh b/genlibs.sh new file mode 100755 index 0000000..3f28fea --- /dev/null +++ b/genlibs.sh @@ -0,0 +1,28 @@ +#!/bin/zsh +# +# Copyright (C) 2009 Nick Bowler +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. +# +# Generate library dependencies for an initramfs. Finds all dynamically linked +# binaries listed in an initramfs description (as needed by gen_init_cpio from +# the Linux source) and passes them to libs.sh in order to actually generate +# the dependencies. + +if [ -z "$1" ]; then + echo "usage: genlibs.sh initramfs-desc" + exit 1 +fi + +files=(`sed -n 's/^ *file \+[^ ]\+ \+\([^ ]\+\).*/\1/p' "$1"`) + +dyns=() + +for i in $files; do + if ! file "$i" | grep dynamic >/dev/null; then continue; fi + dyns+="$i" +done + +./libs.sh $dyns diff --git a/get_extension.zsh b/get_extension.zsh new file mode 100755 index 0000000..090af8e --- /dev/null +++ b/get_extension.zsh @@ -0,0 +1,46 @@ +#!/usr/bin/env zsh +# +# Copyright © 2010-2012 Nick Bowler +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. +# +# A convenient script to download an OpenGL extension specification from the +# Khronos registry into the current working directory. + +IFS=_ extension=(${=1}) + +case $extension[1] in +GL|GLX|WGL) + ;; +*) + extension=(GL $extension) + ;; +esac + +api=$extension[1] +vendor=$extension[2] +name=${(j:_:)extension[3,-1]} +fullname=${(j:_:)extension} + +if [[ -z $api || -z $vendor || -z $name ]]; then + printf 'usage: %s extension\n' $0 1>&2 + exit 1 +fi + +urls=( + http://www.opengl.org/registry/specs/$vendor/$name.txt + http://www.opengl.org/registry/specs/$vendor/${api:l}_$name.txt +) + +for url in $urls; do + if wget -O $fullname $url; then + gzip -f $fullname || exit 1 + exit 0 + fi + + rm -f $fullname +done + +exit 1 diff --git a/gitcvs.zsh b/gitcvs.zsh new file mode 100755 index 0000000..9cc13d9 --- /dev/null +++ b/gitcvs.zsh @@ -0,0 +1,144 @@ +#!/usr/bin/env zsh +# +# Copyright © 2008-2011 Nick Bowler +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +# List all commits that have not yet been committed to CVS. (run this command +# from the root of the CVS repository) +git-cvs-commitlist() { + if [[ -z "$1" ]]; then + echo "usage: git-cvs-commitlist [origin]" 1>&2 + return 1 + fi + + [[ -z "$2" ]] && 2="remotes/CVS/master" + [[ -d "$1/.git" ]] && 1="$1/.git" + + GIT_DIR="$1" git cherry -v "$2" +} + +# Commit a specified commit to CVS (run this command from the root of the CVS +# repository). +git-cvs-commit() { + if [[ -z "$1" || -z "$2" ]]; then + echo "usage: git-cvs-commit " 1>&2 + return 1 + fi + + [[ -d "$1/.git" ]] && 1="$1/.git" + + GIT_DIR="$1" git cvsexportcommit -cvp "$2" +} + +# Commit all commits that are not yet in CVS to CVS. +# (run this command from the root of the CVS repository). +git-cvs-commit-all() { + if [[ -z "$1" ]]; then + echo "usage: git-cvs-commit-all " 1>&2 + return 1 + fi + + git-cvs-commitlist $1 | while read i; do + local commit=$(echo $i | cut -d ' ' -f 2) + git-cvs-commit $1 $commit || return $? + done +} + +# Import the latest and greatest changes into a git repository (will create +# a new repository if run outside of any git repo). +# +# The details used to fetch from CVS are recorded so that running +# git-cvs-fetch with no arguments will repeat the same fetch as last time. +# Currently, some arguments which don't make sense to record are recorded +# anyway, so you may need to manually edit .git/config afterwards... +git-cvs-fetch() { + local tmp cvsroot cvsmod cvsopts + + cvsroot=${$(git config cvs.root):-$CVSROOT} + cvsopts=${$(git config cvs.opts):-'$@'} + eval "cvsopts=($cvsopts)" + + # Extract a CVS root from opts, if any. + while [[ $((tmp=${cvsopts[(i)-d*]})) -le $#cvsopts ]]; do + cvsroot=${cvsopts[$tmp]#-d} + cvsopts=($cvsopts[1,$tmp-1] $cvsopts[$tmp+1,-1]) + if [[ -z $cvsroot ]]; then + cvsroot=${cvsopts[$tmp]} + cvsopts=($cvsopts[1,$tmp-1] $cvsopts[$tmp+1,-1]) + fi + done + + if ! cvsmod=$(git config cvs.module); then + cvsmod=$cvsopts[-1] + cvsopts=($cvsopts[1,-2]) + fi + + # By this point, we must have a CVS root and module. + if [[ -z $cvsroot ]]; then + printf '%s: no CVS root set.\n' $0 1>&2 + return 1 + fi + + if [[ -z $cvsmod ]]; then + printf '%s: no CVS module set.\n' $0 1>&2 + return 1 + fi + + GIT_DIR=`git rev-parse --git-dir 2>/dev/null` git cvsimport \ + -air CVS -d $cvsroot $cvsopts $cvsmod || return 1 + + # Store the settings for this run. + git config cvs.root $cvsroot + git config cvs.module $cvsmod + [[ $#cvsopts -gt 0 ]] && git config cvs.opts ${(j: :)${(qq)cvsopts}} + : +} + +# Generate an excludes file, suitable for writing to .git/info/exclude, based +# on .cvsignore files found in the repository. Run this command from the git +# repository. +git-cvs-genexclude() { + local dir i j cvsdefaults work + + work=`git rev-parse --show-toplevel` || return 1 + if test -z $work; then + printf '%s: must be run from the work tree\n' $0 1>&2 + return 1 + fi + + printf '#\n# Automatically generated by %s\n#\n' "$0 $*" + + # CVS ignores a number of patterns by default. + cvsdefaults=( + 'RCS' 'SCCS' 'CVS' 'CVS.adm' 'RCSLOG' 'cvslog.*' + 'tags' 'TAGS' '.make.state' '.nse_depinfo' + '*~' '#*' '.#*' ',*' '_$*' '*$' + '*.old' '*.bak' '*.BAK' '*.orig' '*.rej' '.del-*' + '*.a' '*.olb' '*.o' '*.obj' '*.so' '*.exe' + '*.Z' '*.elc' '*.ln' 'core' + ) + printf '%s\n' $cvsdefaults + + find $work -name .cvsignore | while read i; do + dir=${$(dirname $i)#$work} + + < $i while read j; do + printf '%s/%s\n' $dir $j + done + done +} + +# For executable-like invocation... + +# It would be nice if we could detect whether we are invoked as an executable +# and print a usage message if not given any arguments. I have yet to find +# a clean way to do this, however. + +if [ $# -gt 0 ]; then + func="git-cvs-${1#git-cvs-}" + shift + "$func" $@ +fi diff --git a/ircmpc.pl b/ircmpc.pl new file mode 100644 index 0000000..138a516 --- /dev/null +++ b/ircmpc.pl @@ -0,0 +1,134 @@ +# Copyright (C) 2008, 2010 Nick Bowler +# +# Irssi script for annoying your friends with MPD status information. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +use strict; +use vars qw($VERSION %IRSSI); + +use utf8; +use encoding 'utf8'; +use IO::Socket::INET6; + +use Irssi qw( + command_bind + settings_get_bool settings_add_bool + settings_get_int settings_add_int + settings_get_str settings_add_str +); + +$VERSION = '0.1'; +%IRSSI = ( + authors => 'Nick Bowler', + contact => 'nbowler@draconx.ca', + name => 'MPC/Irssi', + description => 'Irssi client for the Music Player Daemon.', + license => 'WTFPL2', +); + +# MPD Connection Settings +$ENV{"MPD_HOST"} = "localhost" unless ($ENV{"MPD_HOST"}); +$ENV{"MPD_PORT"} = 6600 unless ($ENV{"MPD_PORT"}); +settings_add_str("mpd", "mpd_host", $ENV{"MPD_HOST"}); +settings_add_int("mpd", "mpd_port", $ENV{"MPD_PORT"}); + +# Open a connection to MPD. +sub mpd_open { + my $sock = new IO::Socket::INET6( + PeerAddr => settings_get_str("mpd_host"), + PeerPort => settings_get_int("mpd_port"), + Proto => 'tcp', + ) or do { + print CLIENTERROR "failed to open MPD socket: $!."; + return undef; + }; + binmode($sock, ":utf8"); + + # Grab the MPD version. + if (!(<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/)) { + print CLIENTERROR "failed MPD handshake: $!."; + return undef; + } + + return $sock; +} + +sub mpd_currentsong { + my ($sock) = @_; + my %data; + + # Get MPD status. + print $sock "status\n"; + while (<$sock>) { + last if (/^OK/); + do { print CLIENTERROR "$_"; return undef } if (/^ACK/); + + if (/^(\w+): (.*)$/) { + $data{$1} = $2; + } + } + return %data if (!defined $data{"songid"}); + + # Get song info + print $sock "playlistid $data{songid}\n"; + while (<$sock>) { + last if (/^OK/); + do { print CLIENTERROR "$_"; return undef } if (/^ACK/); + + if (/^(\w+): (.*)$/) { + $data{$1} = $2; + } + } + + return %data; +} + +sub mpd_close { + my ($sock) = @_; + print $sock "close\n"; + close $sock; +} + +sub fileformat { + ($_) = @_; + + return "vorbis" if (/\.ogg$/); + return "flac" if (/\.flac$/); + return "mp3" if (/\.mp3$/); +} + +sub cmd_current { + my ($data, $server, $witem) = @_; + my ($window, $local) = (Irssi::active_win()); + + my $sock = mpd_open() or return; + my %info = mpd_currentsong($sock) or return; + mpd_close($sock); + + if ($info{'state'} eq "stop") { + $window->print("MPD is currently stopped."); + return; + } + + my $text = "$info{Artist} – $info{Title}, " + . "track $info{Track} of “$info{Album}” " + . "($info{bitrate}kbps " . fileformat($info{'file'}) . ")"; + + # If the active window is not a channel or query, display locally. + $local = 1 unless ($witem && ($witem->{type} eq "CHANNEL" + || $witem->{type} eq "QUERY")); + + if ($local) { + $window->print($text); + } elsif ($data) { + $data =~ s/\s.*//; + $witem->command("SAY $data: /me is listening to $text."); + } else { + $witem->command("SAY /me is listening to $text."); + } +} + +command_bind('mpd', 'cmd_current'); diff --git a/libs.sh b/libs.sh new file mode 100755 index 0000000..228e8ee --- /dev/null +++ b/libs.sh @@ -0,0 +1,63 @@ +#!/bin/zsh +# +# Copyright (C) 2009 Nick Bowler +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. +# +# Determine library dependencies for dynamically linked binaries and output +# directives suitable for gen_init_cpio to include all required libraries +# in an initramfs archive. Users of this script will probably need to adjust +# the BASE, LDD and LOADER variables appropriately. + +# Directory in which the libraries are located. +BASE=/usr/x86_64-pc-linux-uclibc + +# How to run ldd. The uClibc dynamic loader explodes wonderfully if +# LD_LIBRARY_PATH is not set correctly. +LDD="LD_LIBRARY_PATH=$BASE/lib:$BASE/usr/lib x86_64-pc-linux-uclibc-ldd" + +# Where the dynamic loader is located. Always included in the output. +LOADER="/lib/ld64-uClibc.so.0" + +getlibs() { + local file=$1 + + if test -u "$1" -o -g "$1"; then + file=`mktemp` + cp -f "$1" "$file" + fi + + eval "$LDD '$file'" | sed -n 's/.*=> \(.*\) (0x[[:xdigit:]]*)/\1/p' + + if [ "$file" != "$1" ]; then + rm -f "$file" + fi +} + +libs=(`for i in "$@"; do getlibs "$i"; done | sort -u`) + +output="file $LOADER $BASE$LOADER 0755 0 0" + +while [ $#libs -gt 0 ]; do + i=${libs[1]} + libs=(${libs[2,-1]}) + + if ! [[ "$i" =~ "^$BASE" ]]; then continue; fi + + dest=${i#$BASE} + + if test -L "$i"; then + output="$output\nslink $dest $(readlink "$i") 0644 0 0" + next=`readlink "$i"` + if [ "$next[0]" != "/" ]; then + next="$(dirname "$i")/$next" + fi + libs+=$next + elif test -f "$i"; then + output="$output\nfile $dest $i 0644 0 0" + fi +done + +echo "$output" | sort -u diff --git a/maildir-clean.zsh b/maildir-clean.zsh new file mode 100755 index 0000000..ee6438b --- /dev/null +++ b/maildir-clean.zsh @@ -0,0 +1,60 @@ +#!/usr/bin/env zsh +# +# Copyright (C) 2009,2011 Nick Bowler +# +# Delete email older than a given date from a maildir. Assumes that the +# Date headers in the mails are valid and correct, and is therefore +# somewhat less useful for cleaning up spam. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +cutoff='last week' +maildir= + +while getopts 'd:' opt $@; do + case $opt in + d) cutoff=$OPTARG ;; + \?) exit 1 ;; + esac +done + +shift $((OPTIND-1)) + +# Determine maildir +if [[ -n $1 ]]; then + maildir=$1 +elif [[ -n $MAIL ]]; then + maildir=$MAIL +fi + +# Validate arguments +date=`date --rfc-3339=date --date=$cutoff` || exit 1 + +if [[ -z $maildir ]]; then + printf '%s: you must specify a maildir.\n' $0 + exit 1 +fi + +if ! [[ -d $maildir/cur && -d $maildir/new && -d $maildir/tmp ]]; then + printf '%s: %s is not a valid maildir.\n' $0 $maildir + exit 1 +fi + +total=`ls $maildir/cur | wc -l`. +count=0 + +for i in $maildir/cur/*; do + datehdr=`formail -x Date < $i` + maildate=`date --rfc-3339=date --date=$datehdr` + + count=$((count+1)) + + if [[ $maildate < $date ]]; then + printf '(%.0f%%) %s: deleting %s\n' $((100*count/total)) $0 $i + rm -f $i + else + printf '(%.0f%%) %s: keeping %s\n' $((100*count/total)) $0 $i + fi +done diff --git a/modules.zsh b/modules.zsh new file mode 100755 index 0000000..6115d27 --- /dev/null +++ b/modules.zsh @@ -0,0 +1,64 @@ +#!/usr/bin/env zsh +# +# Copyright © 2009 Nick Bowler +# +# Generate module listings for an initramfs by searching a subset of the +# installed modules for a particular kernel version. Currently, all +# filesystem and MD drivers, plus all their (recursive) dependencies, +# are included. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +usage() { + echo "usage: modules.zsh kernel-version" 1>&2 + exit 1 +} + +out_mkdir_p() { + local i base path + base=$1 + path=(${(s./.)2}) + + for i in {1..$#path}; do + echo "dir $base/${(j./.)path[1,i]} 0755 0 0" + done +} + +if [ -z "$1" ]; then + usage +fi + +kver=$1 + +moduledir=/lib/modules/$kver + +if ! [ -d "$moduledir" ]; then + echo "module directory for kernel \`\`$kver'' does not exist." 1>&2 + usage +fi + +kmods=(`find $moduledir/kernel/fs $moduledir/kernel/drivers/md \ + -type f -name '*.ko' -exec basename {} .ko \;`) + +paths=() + +while [ $#kmods -gt 0 ]; do + i=${kmods[1]} + kmods=(${kmods[2,-1]}) + + info=`modinfo -k $kver $i` + paths+=`echo $info | sed -n 's/^filename:[[:space:]]*//p'` + + kmods+=(${(s.,.)$(echo $info | sed -n 's/^depends:[[:space:]]*//p')}) +done + +echo "dir $moduledir 0755 0 0" +echo "file $moduledir/modules.dep $moduledir/modules.dep 0644 0 0" +echo "file $moduledir/modules.alias $moduledir/modules.alias 0644 0 0" +for i in $paths; do + i=${i#$moduledir/} + out_mkdir_p $moduledir $(dirname $i) + echo "file $moduledir/$i $moduledir/$i 0644 0 0" +done | sort -u diff --git a/mpdbetter.sed b/mpdbetter.sed new file mode 100755 index 0000000..a59a4f8 --- /dev/null +++ b/mpdbetter.sed @@ -0,0 +1,52 @@ +#!/bin/sed -f + +# Nick's mpdbetter `configuration file'. Input a list of track titles, and +# substitute each with the title of the best version of that song. + +# Handle special cases first +/ -extra hot mix-/{s///;b} +/ -Raven fly edit-/{s///;b} +/ -2006 memorial mix-/{s///;b} +/ -Practice Track-/{s///;b} +/ On Air Ver\./{s///;b} +/-\[instrumental\]/{s///;b} +/ちいさなヘミソフィア/{s//ヘミソフィア/;b} +/愛のメロディー/{s/\((.*)\)\?$/(soundtrack ver.)/;b} +/COLORS -.*/{s//COLORS/;b} +/ without NATSUMI/{s///;b} + +# Some literal replacements +/松澤由美 - SNOW/c\ +島みやえい子 - SNOW -Album Mix- +/詩月カオリ - Senecio/c\ +詩月カオリ - Senecio -Album Mix- +/AKI - Pure Heart〜世界で一番アナタが好き〜/c\ +詩月カオリ - Pure Heart 〜世界で一番アナタが好き〜 -Remix- +/open〜オルゴールバージョン〜/c\ +詩月カオリ - open +/euphoric field/c\ +ELISA - euphoric field (Japanese) +/La Clef 〜迷宮の鍵〜/c\ +KOTOKO - La Clef 〜迷宮の鍵〜 + +# Sanitization +s/「\(The Sore Feet Song\)」/\1/ + +# General rules get most tracks +/\s*[~〜<〈[(ー–−-]\s\?inst.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?tv.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?without.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?w\/o.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?off.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?back.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?short.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?karaoke.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?game.*/I {s///;b} +/\s*[~〜<〈[(ー–−-]\s\?[^ ]*カラオケ.*/I {s///;b} + +# When we lack brackets we match more specific strings +/ instrumental.*/I {s///;b} +/ off vocal.*/I {s///;b} +/ short.*/I {s///;b} +/ tv-\w\+/I {s///;b} +/ anime ver\./I {s///;b} diff --git a/mpdscripts.sh b/mpdscripts.sh new file mode 100755 index 0000000..ad390f3 --- /dev/null +++ b/mpdscripts.sh @@ -0,0 +1,239 @@ +#!/bin/zsh +# +# Collection of shell functions for manipulating MPD. Functions prefixed with +# __ are intended for use in these scripts, whereas functions prefixed with +# "mpd" are intended to be called by users. +# +# This file may be sourced by your shell startup scripts in order to load all +# the functions into the environment, or it may be invoked as an executable. +# The first argument to the script designates the function, with or without +# the leading "mpd". Subsequent arguments are passed to the called function. +# +# For example, you might run: +# `source mpdscripts.sh' followed by `mpdlist mycoolsong' +# or equivalently: +# `./mpdscripts.sh list mycoolsong'. +# The latter form is useful when not invoking the scripts from a shell. +# +# This version specifies the functions: +# mpdnext, mpdbetter, mpdlist, mpdalbum, and mpdshow. +# +# See the comments above each function for more details. +# +# Requires mpc, GNU grep and GNU sed. +# Works with zsh or bash. +# +# Send questions or comments to nbowler@draconx.ca, or find me on IRC as +# Draconx on irc.freenode.net. +# +# Licensed under the terms of the Do What The Fuck You Want To Public License. +# +############################################################################## + +__mpd_playlist() +{ + mpc --format='%position%) %artist% - %title%' playlist +} + +# __mpd_trackid [regexp] +# With a regular expression as an argument, search the MPD playlist for the +# track matching the expression and print the index of that track. Otherwise, +# print the index of the currently playing track. +__mpd_trackid() +{ + local id + + if [ -z "$1" ]; then + id=`mpc | sed -n "2{s/.*#//;s/\/.*//p}"` + else + id=`__mpd_playlist | sed -n \ + "/${1//\//\\\/}/I{s/^[^[:digit:]]//;s/).*//p;q}"` + fi + + [ -z "$id" ] && return 1 + + echo "$id" + return 0 +} + +# __mpd_trackname [id] +# With a track ID as an argument, print the title of that track. Otherwise, +# print the title of the currently playing track. +__mpd_trackname() +{ + local title + + if [ -z "$1" ]; then + title=`mpc | sed -n "1h;2{g;p;q}"` + else + title=`__mpd_playlist | sed -n \ + "/^[^[:digit:]]*$1)/s/^.[0-9]*) //p"` + fi + + [ -z "$title" ] && return 1 + + echo "$title" + return 0 +} + +# mpdnext [advance] +# Searches the playlist for a track matching , then moves it to the +# position following the currently playing track. If [advance] is a non-empty +# string, also run `mpc next' to play the moved track immediately. +mpdnext() +{ + local index target name + + if [ -z "$1" ]; then + echo "usage: mpdnext " + return 1 + fi + + if ! index=`__mpd_trackid`; then + echo "mpdnext: MPD is currently stopped." + return 1 + fi + + if ! target=`__mpd_trackid "$1"`; then + echo "mpdnext: target not found." + return 1 + fi + + name=`__mpd_trackname $((target))` + + if [ $target -lt $index ]; then + mpc move $target $index + elif [ $target -gt $index ]; then + mpc move $target $((index+1)) + else + echo "mpdnext: selected the playing track" + return 1 + fi + + echo "mpdnext: $name moved." + + # Play track if desired + [ -n "$2" ] && mpc next + + return 0 +} + +# mpdbetter [sedscript] +# Processes the title of the currently playing song through the sed program +# specified by [sedscript] (or ~/.mpdbetter if not specified). If the +# resulting title is different, attempt to find it in the playlist and use +# mpdnext to play it immediately. +mpdbetter() +{ + local title better script="$HOME/.mpdbetter" + [ -n "$1" ] && script="$1" + + if ! title=`__mpd_trackname`; then + echo "mpdbetter: MPD is currently stopped." + return 1 + fi + + if ! better=`echo "$title" | sed -f "$script"`; then + echo "mpdbetter: error in script: \`$script'" + return 1 + fi + + if [ "$better" = "$title" ]; then + echo "mpdbetter: nothing to be done." + return 1 + fi + + mpdnext ") $better\$" next +} + +# mpdlist [regexp] +# Simply search the playlist for tracks matching [regexp], or print the entire +# playlist if [regexp] is not specified. +mpdlist() +{ + if [ -z "$1" ]; then + __mpd_playlist + else + __mpd_playlist | grep --color=auto -i -- "$1" + fi +} + +# mpdshow +# Display the currently playing track as well as the part of the playlist +# surrounding that track. +mpdshow() +{ + local index + + if ! index=`__mpd_trackid`; then + echo "mpdshow: MPD is currently stopped." + return 1 + fi + + mpc + echo + __mpd_playlist | grep -C 5 --color=auto "^$index)" +} + +# mpdalbum +# Search the playlist for tracks belonging to an album matching . +# Print those tracks grouped by album and sorted by track number. +mpdalbum() +{ + local current list + + if [ -z "$1" ]; then + echo "usage: mpdalbum " + return 1 + fi + + # This horrible hack grabs the relevant playlist entries and separates + # desired fields with @!@ and !@!. + list="`mpc --format $'\n%album%\n%track%\n%artist% - %title%' playlist \ + | sed -n " + /^.[0-9]*) $/{ + h;n + /${1//\//\\\/}/I{ + x;G;s/$/@!@/ + N;s/$/!@!/ + N;s/\n//g + p + } + } + " + `" + +# list="`mpc --format '%album%@!@%track%!@!%artist% - %title%' playlist |\ +# sed -n 'h;s/@!@.*//;'"/${1//\//\\\/}/I{g;p}" | sort -k 2`" + + if [ -z "$list" ]; then + echo "mpdalbum: no matches for \`$1'" + return 1 + fi + + echo "$list" | while read i; do + local album="`echo $i | sed 's/.[0-9]*) \(.*\)@!@.*/\1/'`" + local index="`echo $i | sed 's/[# >]\?\([0-9]*\)).*/\1/'`" + local title="`echo $i | sed 's/.*!@!//'`" + + if [ "$album" != "$current" ]; then + [ -n "$current" ] && echo + echo "$album" + current="$album" + fi + + echo -e " $index)\t$title" + done +} + +# For executable-like invocation... + +# It would be nice if we could detect whether we are invoked as an executable +# and print a usage message if not given any arguments. I have yet to find +# a clean way to do this, however. + +if [ $# -gt 0 ]; then + func="mpd${1#mpd}" + shift + "$func" $@ +fi diff --git a/mplus-t-gen.py b/mplus-t-gen.py new file mode 100755 index 0000000..d95702a --- /dev/null +++ b/mplus-t-gen.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# coding=utf-8 +# +# Copyright © 2011 Nick Bowler +# +# Generates new M+ fonts with the CJK characters enlarged, based on the IPAG +# versions. This gives better proportions relative to DejaVu Sans Mono in +# rxvt-unicode. +# +# Run this script in a directory containing the M+ fonts. The new fonts will +# be called M+1T+IPAG and M+2T+IPAG. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +import fontforge as ff +import psMat +import re + +families = [ "M+1M+IPAG", "M+2M+IPAG" ] +scripts = [ "hani", "kana" ] + +for family in families: + font = ff.open(family + ".ttf") + + font.familyname = re.sub(r"(\d)M", r"\1T", font.familyname) + font.fontname = font.familyname + "-Regular" + font.fullname = font.familyname + " Regular" + + for glyph in font.selection.all().byGlyphs: + for s in scripts: + if (glyph.script == s): + glyph.transform(psMat.scale(1.35)) + + print "Generating " + font.familyname + ".ttf" + font.generate(font.familyname + ".ttf") + font.close() diff --git a/musicstats.zsh b/musicstats.zsh new file mode 100755 index 0000000..c5b9a95 --- /dev/null +++ b/musicstats.zsh @@ -0,0 +1,61 @@ +#!/usr/bin/env zsh +# +# Copyright © 2009 Nick Bowler +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +sizes=0 +while getopts 's' opt $@; do + case $opt in + s) sizes=1 ;; + \?) exit 1 ;; + esac +done + +shift $((OPTIND-1)) + +if [[ $# == 0 ]]; then + printf 'usage: %s [-s] directory [directory ...]\n' $0 + exit 1 +fi + +alias mfind='find $@ -type f' +flac=`mfind -name '*.flac' | wc -l` +vorbis=`mfind -name '*.ogg' | wc -l` +mp3=`mfind -name '*.mp3' | wc -l` +total=$((flac+vorbis+mp3)) + +if [[ $total == 0 ]]; then + printf '0 tracks.\n' + exit +fi + +printf '%d tracks: %d (%.1f%%) flac, %d (%.1f%%) vorbis, %d (%.1f%%) mp3.\n' \ + $total \ + $flac $((100.0*flac /total)) \ + $vorbis $((100.0*vorbis/total)) \ + $mp3 $((100.0*mp3 /total)) + +if [[ $sizes == 1 ]]; then + alias getsize="du -mc --files0-from=- | sed -n '\$s/\ttotal$//p'" + float totalsize=`mfind -print0 | getsize` + float flacsize=`mfind -name '*.flac' -print0 | getsize` + float vorbissize=`mfind -name '*.ogg' -print0 | getsize` + float mp3size=`mfind -name '*.mp3' -print0 | getsize` + + if [[ $totalsize -gt 4000 ]]; then + printf 'size: %.1fG total, %.1fG flac, %.1fG vorbis, %.1fG mp3.\n' \ + $((totalsize/1024)) \ + $((flacsize/1024)) \ + $((vorbissize/1024)) \ + $((mp3size/1024)) + else + printf 'size: %.1fM total, %.1fM flac, %.1fM vorbis, %.1fM mp3.\n' \ + $((totalsize)) \ + $((flacsize)) \ + $((vorbissize)) \ + $((mp3size)) + fi +fi diff --git a/openexec.c b/openexec.c new file mode 100644 index 0000000..8cce5f9 --- /dev/null +++ b/openexec.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2011 Nick Bowler + * + * The Mutt email client opens mail attachments with external programs + * synchronously: the attachment is decoded and saved to /tmp, the filename + * is passed to the program to be run, and when the program exits, the file + * is unlinked. This leads to an obvious problem: if the attachment-viewing + * program runs in the foreground, one cannot interact with mutt until you + * quit it. If the program runs in the background, then there is a race + * between the program opening the file and mutt unlinking it. + * + * This tool solves this problem by opening all files and spawning a program + * in the background. It is safe to unlink the files after they are opened, + * so the race with mutt is avoided. + * + * License WTFPL2: Do What The Fuck You Want To Public License, version 2. + * This is free software: you are free to do what the fuck you want to. + * There is NO WARRANTY, to the extent permitted by law. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +static const char *progname = "openexec"; +static const char sopts[] = "-VH"; +static const struct option lopts[] = { + { "version", 0, NULL, 'V' }, + { "help", 0, NULL, 'H' }, + { 0 } +}; + +static void print_version(void) +{ + puts("openexec version 1.0"); + puts("\ +Copyright (C) 2011 Nick Bowler.\n\ +License WTFPL2: Do What The Fuck You Want To Public License, version 2.\n\ +This is free software: you are free to do what the fuck you want to.\n\ +There is NO WARRANTY, to the extent permitted by law.\ + "); +} + +static void print_usage(FILE *f) +{ + fprintf(f, "Usage: %s [options] [file ...] -- program [arguments]\n", + progname); +} + +static void print_help(void) +{ + print_usage(stdout); + puts("Detailed help coming eventually."); +} + +static char *fake_open(const char *filename) +{ + char *buf; + int n, fd; + + fd = open(filename, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "%s: %s: %s\n", progname, filename, + strerror(errno)); + return NULL; + } + + n = snprintf(NULL, 0, "/proc/self/fd/%d", fd); + buf = malloc(n+1); + if (!buf) { + close(fd); + fprintf(stderr, "%s: %s\n", progname, strerror(errno)); + return NULL; + } + + sprintf(buf, "/proc/self/fd/%d", fd); + return buf; +} + +int main(int argc, char **argv) +{ + int nargs = 0, opt, rc, err, fds[2]; + + if (argc > 0) + progname = argv[0]; + + char *args[argc]; + + while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { + switch (opt) { + case 1: + args[nargs] = fake_open(optarg); + if (!args[nargs]) + return EXIT_FAILURE; + nargs++; + break; + case 'V': + print_version(); + return EXIT_SUCCESS; + case 'H': + print_help(); + return EXIT_SUCCESS; + default: + print_usage(stderr); + return EXIT_FAILURE; + } + } + + if (!argv[optind]) { + print_usage(stderr); + return EXIT_FAILURE; + } + + args[nargs] = NULL; + memmove(args + (argc - optind), args, (nargs + 1) * sizeof *args); + memcpy(args, argv + optind, (argc - optind) * sizeof *args); + + /* + * We use a close-on-exec pipe for the child to signal success/failure + * to the parent. On successful exec, the write end of the pipe will + * be closed, causing the read in the parent to return 0. On failure, + * errno will be written to the pipe, allowing the parent to print + * an error message. + */ + rc = pipe2(fds, O_CLOEXEC); + if (rc == -1) { + fprintf(stderr, "%s: pipe2: %s\n", progname, strerror(errno)); + return EXIT_FAILURE; + } + + switch (fork()) { + case -1: + fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); + return EXIT_FAILURE; + case 0: + execvp(args[0], args); + + /* This horrible if statement shuts up GCC... */ + err = errno; + if (write(fds[1], &err, sizeof err)) + ; + _Exit(EXIT_FAILURE); + } + + close(fds[1]); + rc = read(fds[0], &err, sizeof err); + if (rc == -1) { + /* No information about the child's state. */ + fprintf(stderr, "%s: read: %s\n", progname, strerror(errno)); + return EXIT_FAILURE; + } else if (rc == 0) { + /* Exec was successful, so we are too. */ + return EXIT_SUCCESS; + } + + /* Exec in the child failed, print the error we received on the pipe. */ + fprintf(stderr, "%s: %s: %s\n", progname, args[0], strerror(err)); + return EXIT_FAILURE; +} diff --git a/polya.tex b/polya.tex new file mode 100644 index 0000000..4a32eb9 --- /dev/null +++ b/polya.tex @@ -0,0 +1,72 @@ +\documentclass{article} + +\usepackage{fullpage} +\usepackage{amssymb} +\usepackage{tikz} + +% Peano Curve of Polya +\newcounter{polyax} +\newcounter{polyay} +\newcounter{polyaz} +\newcounter{polyap} + +\newcommand{\polyafig}[3]{ + \coordinate (p0) at (#1); + \coordinate (p1) at +(0:#2); + \coordinate (p2) at (intersection cs: + first line={(p0)--+(60:1)}, + second line={(p1)--($(p1)!1!150:(p0)$)}); + \draw (p0) -- (p1) -- (p2) --cycle; + + \coordinate (p3) at ($(p0)!(p2)!(p1)$); + \draw[densely dotted] (p2) -- (p3); + + \setcounter{polyax}{0} + \setcounter{polyay}{2} + \setcounter{polyaz}{1} + \setcounter{polyap}{3} + + \foreach \d in {#3} { + \pgfmathtruncatemacro{\x}{\thepolyax} + \pgfmathtruncatemacro{\y}{\thepolyay} + \pgfmathtruncatemacro{\z}{\thepolyaz} + + \ifthenelse{\equal{\d}{1}}{ + \pgfmathtruncatemacro{\xx}{\y} + \pgfmathtruncatemacro{\zz}{\z} + }{ + \pgfmathtruncatemacro{\xx}{\x} + \pgfmathtruncatemacro{\zz}{\y} + } + \pgfmathtruncatemacro{\yy}{\y+1} + + \pgfmathtruncatemacro{\v}{\yy+1} + \coordinate (p\v) at + ($(p\xx)!(p\yy)!(p\zz)$); + \draw[densely dotted] (p\yy) -- (p\v); + + \setcounter{polyax}{\xx} + \setcounter{polyay}{\yy} + \setcounter{polyaz}{\zz} + \setcounter{polyap}{\v} + } +} + +\title{The Peano Curve of P\'olya} +\author{} +\date{} + +\begin{document} +\maketitle + +A \emph{Peano Curve} is a curve which hits every point in a two-dimensional +object. Recall that a curve is a continuous function +\[ +f : [0,1] \to \mathbb{R}^2. +\] +A famous example of such a curve is due to George P\'olya, which fills a +right-angled triangle. For $x \in [0,1)$, let $\{a_n\}^\infty_{n=0}$ be the +sequence of digits after the decimal point in its binary expansion. If there +are multiple binary expansions, either will do (the result is the same). + +\end{document} diff --git a/quine.hs b/quine.hs new file mode 100644 index 0000000..e75a8f9 --- /dev/null +++ b/quine.hs @@ -0,0 +1,2 @@ +listing = "main = putStr \"listing = \" >> print listing >> putStrLn listing" +main = putStr "listing = " >> print listing >> putStrLn listing diff --git a/quine.sed b/quine.sed new file mode 100755 index 0000000..af00345 --- /dev/null +++ b/quine.sed @@ -0,0 +1,28 @@ +#!/bin/sed -nf +# A quine for GNU sed. +s:.*: i\\\ + #!/bin/sed -nf\\\ + # A quine for GNU sed.\ + h\ + s/\\\\/\\\\\\\\/g\ + s/\&/\\\\\&/g\ + s/\:/\\\\\:/g\ + s/\\n/\\\\\\n/g\ + s/.*/s\:.*\:\&\:/\ + p\ + g\ + s/ \\{2,\\}//g\ + p: +i\ +#!/bin/sed -nf\ +# A quine for GNU sed. +h +s/\\/\\\\/g +s/&/\\&/g +s/:/\\:/g +s/\n/\\\n/g +s/.*/s:.*:&:/ +p +g +s/ \{2,\}//g +p diff --git a/replaygain.zsh b/replaygain.zsh new file mode 100755 index 0000000..89b293f --- /dev/null +++ b/replaygain.zsh @@ -0,0 +1,64 @@ +#!/usr/bin/env zsh +# +# Copyright (C) 2009 Nick Bowler +# +# Adds replaygain tags to the flac files in a directory. Assumes that all +# the tracks from a CD are located in the same directory. Unless the -f flag +# is specified, directories already containing replaygain tags will not be +# processed. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +alias flactags='metaflac --export-tags-to=-' + +is_disc_dir() { + local files + + [[ -d $1 ]] || return 1 + + files=($1/*.flac(N)) + [[ $#files > 0 ]] || return 1 +} + +has_replay_gain() { + local files + + files=($1/*.flac(N)) + for i in $files; do + (flactags $i | grep -q REPLAYGAIN_REFERENCE) || return 1 + done +} + +force=0 +while getopts 'f' opt $@; do + case $opt in + f) force=1 ;; + \?) exit 1 ;; + esac +done + +shift $((OPTIND-1)) + +if [[ $# == 0 ]]; then + printf 'usage: %s [-f] directory [directory ...]\n' $0 + exit 1 +fi + +for dir in $@; do + printf '%s: ' $dir + + if ! is_disc_dir $dir; then + printf 'not an album directory, skipping.\n' + continue + fi + + if [[ $force == 0 ]] && has_replay_gain $dir; then + printf 'already done, skipping.\n' + continue + fi + + metaflac --add-replay-gain $dir/*.flac + printf 'done.\n' +done diff --git a/runcron.zsh b/runcron.zsh new file mode 100755 index 0000000..8248728 --- /dev/null +++ b/runcron.zsh @@ -0,0 +1,24 @@ +#!/usr/bin/env zsh +# +# Copyright © 2011 Nick Bowler +# +# Simple script to dispatch jobs in /etc/cron.whatever. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +crondir=/etc/cron.$1 + +if ! [[ -d $crondir ]]; then + printf '%s: argument must be one of:' $0 + for i in /etc/cron.*; do + if ! [[ -d $i ]]; then continue; fi + printf ' %s' ${i#/etc/cron.} + done + echo . + + exit 1 +fi + +run-parts --verbose --regex='^[^.][[:alnum:]_.-]+$' $crondir diff --git a/spamassassin.zsh b/spamassassin.zsh new file mode 100755 index 0000000..becf6b6 --- /dev/null +++ b/spamassassin.zsh @@ -0,0 +1,29 @@ +#!/usr/bin/env zsh +# +# Copyright © 2011 Nick Bowler +# +# Check mail for spam, automatically spawning spamd as necessary. This +# script can therefore be used in a procmail recipe to efficiently handle +# spam filtering. +# +# Runs plain old spamassassin if the daemon cannot be started for any reason. +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +spamd_sock=$HOME/.spamd +spamd_log=$HOME/.spamdlog +spamd_pid=$HOME/.spamdpid +spamd=/usr/sbin/spamd + +run_spamd() { + flock -n $spamd_pid $spamd --pidfile=$spamd_pid --syslog=$spamd_log \ + --socketpath=$spamd_sock $@ +} + +if ! spamc -K -U $spamd_sock &>/dev/null; then + run_spamd --daemonize || exec spamassassin +fi + +exec spamc -U $spamd_sock -- 2.43.0