Bald
Well, the time finally came and so my hair went. Involuntarily, this time.
Now, these pictures aren't very high resolution so you may not be able to tell, but this first shave isn't particularly close. Even then it took awhile to do. I'm going to shave it every day until I get a reasonably close shave (I'm thinking tomorrow I should get pretty close), then I'll take some higher-resolution pictures and wear something more tough-looking, so you can all feel properly intimidated.
I mostly used a 2-blade cartridge razor, but I was getting annoyed with it doing basically nothing and tried switching to the safety razor a few times. This worked well on the parts I could see in the mirror, but it would take some practice to be able to shave the back with a safety razor because you have to get the angle right and some foresight on the upcoming curves helps a lot.
The HeadBlade seems to be popular for getting a good and quick shave. It's only $13 and my local WalGreens has it, so if I decide to stick with it I may not be able to resist trying it out (it's called Brush/Soap/Razor Acquisition Disorder). The downside would of course be that it uses expensive cartridges and there's something like 3x as much hair on your pate as your face. DE blades are much cheaper in the long haul. I wonder if there is a HeadBlade DE adapter…
How Short?
My hair on top has thinned to the point that my old standby hairstyle is now dysfunctional. So now I have to decide what to do. Should I shave it? Buzz it? Grow it long? Short but not quite buzzed? If you have any idea (as if anyone cares) now is the time to weigh in.
Pictures of the situation are here.
Bread PDF Update
I've updated my bread/sourdough PDF to reflect the recipe and methods I have settled on.
The bread recipe didn't really change, though I adjusted a few minor details in wording, etc. The sourdough pancakes recipe is completely new—the one from Joe Pastry which is so much better than the one I came up with. The biscuit recipe is the old biscuit recipe from the old sourdough cards that my family got with our start. I don't know if that source has a name or author, but I do have scanned images at http://hans.fugal.net/sourdough/. The consensus of all who eat these biscuits is that they must be served at Thanksgiving dinner in Heaven.

IMMS
So Apple added this Genius thing to iTunes recently. Not being the type to get excited about new iPod styles, it looks like the most interesting thing they could come up with this year. I gave it a try. I am not impressed.
I think it's because I've been spoiled. 5 years ago I was using what I still consider to be the peak of intelligent listening software, IMMS. Genius isn't half as cool as IMMS was then, and while IMMS hasn't made any quantum leaps in coolness, quite a few rough edges have been rounded off in the meantime.
I've been living in a sort of IMMS drought the past couple of years, since I switched to using a laptop primarily. Namely, an Apple laptop. This Genius release spurred me on to rectify that situation. If the best Apple could do was generate a 25-song playlist based on statistics gathered from other people the hopes of someone else hacking up an iTunes plugin to do IMMS or something like it dwindled to obscurity.
The bane of IMMS is, ironically, its most compelling feature. IMMS is cool because you don't have to do anything. It pays attention to your listening habits, and analyzes the audio, and makes intelligent decisions for you when you turn on random. 4 years ago I would show up to work and be in a Depeche Mode mood, so I'd manually queue up a Depeche Mode song or two and the whole day I'd be treated to complementary music. If the occasional happy song slipped through, I just skipped it and IMMS took the hint. Don't underestimate the amazing wow factor of a computer apparently reading your mind.
But this focus on simple non-obtrusive UI has been its biggest technical struggle. Media players are now a dime a dozen, and few of them have the plugin and UI sophistication to support IMMS' modus operandi. IMMS was developed originally as a plugin for XMMS and even then ugly workaround hacks were required. Then someone wrote a queue control patch for XMMS, and if you patched your XMMS you were in heaven. Oh, did I mention that still almost no other media players even have queue functionality, let alone let the plugins control the queue? Then when you consider the set of media players usable on OS X the situation gets laughable.
Somewhere in the middle MPD came along. It fit my situation well because the speakers over on the desktop were a lot nicer than the ones in my laptop. But queues it has not and nobody seems to care. Von bravely came up with an IMMS hack for MPD, but it was too hacky for me—too much like the old XMMS days before the queue control patch (incidentally, queue control is part of XMMS proper now as of version 1.2.11).
So I suffered along with manual or truly random music listening. Until now.
Recently I looked into this again for the desktop, and I was delighted to discover that one of the many XMMS descendants has finally solved the XMMS bitrot without throwing the baby out with the bathwater. Audacious is as cool as XMMS ever was and as modern as your favorite modern player (unless you measure modern by klunky iTunes-like screen-wasting music browsers). What's more, the imms plugin for it is right there in the Ubuntu repository. Just apt-get install imms-audacious and enable the plugin and you're off and running. So I set it up and… didn't use it. As in, we rarely listen to music on the desktop because nobody really sits there for very long. So finally earlier this week I hammered out a simple remote control using Audacious' dbus interface. That's another post, once I knock off a few other TODO points.
Feeling on a roll and feeling left out when at school, I decided to get an IMMS solution on my laptop, running OS X Leopard (10.5.4). I'll spare you the agonizing play-by-play and give you the shortest path to success: install Audacious and then IMMS. Actually the really shortest path is to install XMMS and then IMMS, because XMMS is in MacPorts. But it's the old version of XMMS without queue control, and doesn't have CoreAudio support (you have to use the JACK output plugin) so I don't recommend that.
To install Audacious, install its dependencies (mostly using MacPorts), then build it and its plugins. Installing its dependencies is the hardest part because it's difficult to locate libmcs and libmowgli (they're not where the README says they are, and Google is less than helpful). I just ended up stealing the *.orig.tar.gz files from the Ubuntu packages (apt-get source -d libmcs1 libmowgli). There is one patch you need for the plugins.
src/CoreAudio/audio.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
Index: audacious-plugins-1.5.1/src/CoreAudio/audio.c
===================================================================
--- audacious-plugins-1.5.1.orig/src/CoreAudio/audio.c 2008-09-19 12:08:01.000000000 -0600
+++ audacious-plugins-1.5.1/src/CoreAudio/audio.c 2008-09-19 12:10:28.000000000 -0600
@@ -326,7 +326,12 @@ gint osx_get_output_time(void)
{
gint retval;
- retval = output_time_offset + ((output_total * sample_size * 1000) / output.bps);
+ if (output.bps == 0)
+ {
+ printf("Avoiding divide by zero in osx_get_output_time()\n");
+ retval = 0;
+ } else
+ retval = output_time_offset + ((output_total * sample_size * 1000) / output.bps);
retval = (int)((float)retval / user_pitch);
//printf("osx_get_output_time(): time is %d\n",retval);
Next you need to install IMMS. This is a bit more involved, but should be straightforward with these patches. I'll put them here and talk about each in turn.
First, a missing include for mkdir()
immsd/immsd.cc | 1 +
1 file changed, 1 insertion(+)
Index: imms-3.1.0-rc4/immsd/immsd.cc
===================================================================
--- imms-3.1.0-rc4.orig/immsd/immsd.cc 2008-03-02 18:54:06.000000000 -0700
+++ imms-3.1.0-rc4/immsd/immsd.cc 2008-09-19 08:05:58.000000000 -0600
@@ -2,6 +2,7 @@
#include <errno.h>
#include <signal.h>
#include <unistd.h>
+#include <sys/stat.h>
#include <iostream>
#include <sstream>
Then, a workaround due to OS X not having an initstate_r() (which I
incidentally couldn't find in the current Linux manpages on Ubuntu or Debian
either). This patch may not apply cleanly by itself, you may need to apply your
cognitive reasoning.
configure.ac | 3 +++
immsconf.h | 3 +++
immsconf.h.in | 3 +++
immscore/immsutil.cc | 9 +++++++++
4 files changed, 18 insertions(+)
Index: imms-3.1.0-rc4/immscore/immsutil.cc
===================================================================
--- imms-3.1.0-rc4.orig/immscore/immsutil.cc 2008-03-02 18:54:06.000000000 -0700
+++ imms-3.1.0-rc4/immscore/immsutil.cc 2008-09-19 08:13:29.000000000 -0600
@@ -27,6 +27,7 @@ int imms_random(int max)
{
int rand_num;
static bool initialized = false;
+#ifndef INITSTATE_BUG
static struct random_data rand_data;
static char rand_state[256];
if (!initialized)
@@ -36,6 +37,14 @@ int imms_random(int max)
initialized = true;
}
random_r(&rand_data, &rand_num);
+#else
+ if (!initialized)
+ {
+ srandom(time(0));
+ initialized = true;
+ }
+ rand_num = random();
+#endif
double cof = rand_num / (RAND_MAX + 1.0);
return (int)(max * cof);
}
Index: imms-3.1.0-rc4/configure.ac
===================================================================
--- imms-3.1.0-rc4.orig/configure.ac 2008-03-02 18:54:06.000000000 -0700
+++ imms-3.1.0-rc4/configure.ac 2008-09-19 08:17:58.000000000 -0600
@@ -68,6 +68,9 @@ else
AC_MSG_RESULT([yes])
fi
+AC_DEFINE(INITSTATE_BUG,, [initstate_r is buggy])
+
+
AC_CHECK_LIB(z, compress,, [with_zlib=no])
AC_CHECK_HEADERS(zlib.h,, [with_zlib=no])
if test "$with_zlib" = "no"; then
Index: imms-3.1.0-rc4/immsconf.h
===================================================================
--- imms-3.1.0-rc4.orig/immsconf.h 2008-09-19 08:05:31.000000000 -0600
+++ imms-3.1.0-rc4/immsconf.h 2008-09-19 08:18:23.000000000 -0600
@@ -121,6 +121,9 @@
/* Define to 1 if you have the <zlib.h> header file. */
#define HAVE_ZLIB_H 1
+/* initstate_r is buggy */
+#define INITSTATE_BUG /**/
+
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "mag@luminal.org"
Index: imms-3.1.0-rc4/immsconf.h.in
===================================================================
--- imms-3.1.0-rc4.orig/immsconf.h.in 2008-09-19 07:48:52.000000000 -0600
+++ imms-3.1.0-rc4/immsconf.h.in 2008-09-19 08:16:32.000000000 -0600
@@ -120,6 +120,9 @@
/* Define to 1 if you have the <zlib.h> header file. */
#undef HAVE_ZLIB_H
+/* initstate_r is buggy */
+#undef INITSTATE_BUG
+
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
This patch is just so libpcre can be found
build/Makefile | 1 +
1 file changed, 1 insertion(+)
Index: imms-3.1.0-rc4/build/Makefile
===================================================================
--- imms-3.1.0-rc4.orig/build/Makefile 2008-03-02 18:54:06.000000000 -0700
+++ imms-3.1.0-rc4/build/Makefile 2008-09-19 12:25:05.000000000 -0600
@@ -18,6 +18,7 @@ libimmscore.a: $(call objects,../immscor
libmodel.a: $(call objects,../model) svm-similarity-data.o
$(AR) $(ARFLAGS) $@ $(filter %.o,$^)
+immstool-LIBS=`pcre-config --libs`
immstool: immstool.o libmodel.a libimmscore.a
training_data: training_data.o libmodel.a libimmscore.a
train_model: train_model.o libmodel.a libimmscore.a
Linking shared libraries on OS X is so much different from on Linux that there is almost always a need to do a patch something like this.
rules.mk | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
Index: imms-3.1.0-rc4/rules.mk
===================================================================
--- imms-3.1.0-rc4.orig/rules.mk 2008-09-19 09:04:13.000000000 -0600
+++ imms-3.1.0-rc4/rules.mk 2008-09-19 12:25:50.000000000 -0600
@@ -14,9 +14,8 @@ link = $(CXX) $(filter-out %.a,$1) $(fil
%.o: %.c; $(call compile, $(CC), $<, $@, $($*-CFLAGS) $(CFLAGS) $($*-CPPFLAGS) $(CPPFLAGS))
%: %.o; $(call link, $^ $($*-OBJ) $(LIBS), $@, $($*-LIBS) $(LDFLAGS))
%.so:
- $(CXX) $^ $($*-OBJ) $($*-LIBS) $(LIBS) \
- $(LDFLAGS) \
- -shared -Wl,-z,defs,-soname,$@ -o $@
+ gcc -flat_namespace -undefined suppress -o $@ -bundle $^ $($*-OBJ) $($*-LIBS) $(LIBS) \
+ $(LDFLAGS) -o $@
%-data.o: %
$(OBJCOPY) -I binary -O $(OBJCOPYTARGET) -B $(OBJCOPYARCH) --rename-section .data=.rodata,alloc,load,readonly,data,contents $< $@
This final patch fixes IMMS to use the proper interface for audacious (seems like this would have to be done anywhere?)
clients/audacious/audaciousinterface.c | 177 +++++++++++++++++++++++++++++++++
clients/audacious/rules.mk | 2
2 files changed, 178 insertions(+), 1 deletion(-)
Index: imms-3.1.0-rc4/clients/audacious/audaciousinterface.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ imms-3.1.0-rc4/clients/audacious/audaciousinterface.c 2008-09-19 15:30:21.000000000 -0600
@@ -0,0 +1,177 @@
+#include <gtk/gtk.h>
+
+#ifdef BMP
+#include <bmp/configdb.h>
+#include <bmp/util.h>
+#include <bmp/plugin.h>
+#elif AUDACIOUS
+#include <audacious/configdb.h>
+#include <audacious/util.h>
+#include <audacious/plugin.h>
+#endif
+#include "immsconf.h"
+#include "cplugin.h"
+
+
+int use_xidle = 1;
+int poll_tag = 0;
+
+GtkWidget *configure_win = NULL, *about_win = NULL, *xidle_button = NULL;
+
+gint poll_func(gpointer unused)
+{
+ imms_poll();
+ return TRUE;
+}
+
+void read_config(void)
+{
+ ConfigDb *cfgfile;
+
+ if ((cfgfile = cfg_db_open()) != NULL)
+ {
+ cfg_db_get_int(cfgfile, "imms", "xidle", &use_xidle);
+ cfg_db_close(cfgfile);
+ }
+}
+
+void init(void)
+{
+ imms_init();
+ read_config();
+ imms_setup(use_xidle);
+ poll_tag = gtk_timeout_add(200, poll_func, NULL);
+}
+
+void cleanup(void)
+{
+ imms_cleanup();
+
+ if (poll_tag)
+ gtk_timeout_remove(poll_tag);
+
+ poll_tag = 0;
+}
+
+void configure_ok_cb(gpointer data)
+{
+ ConfigDb *cfgfile = cfg_db_open();
+
+ use_xidle = !!GTK_TOGGLE_BUTTON(xidle_button)->active;
+
+ cfg_db_set_int(cfgfile, "imms", "xidle", use_xidle);
+ cfg_db_close(cfgfile);
+
+ imms_setup(use_xidle);
+ gtk_widget_destroy(configure_win);
+}
+
+#define ADD_CONFIG_CHECKBOX(pref, title, label, descr) \
+ pref##_frame = gtk_frame_new(title); \
+ gtk_box_pack_start(GTK_BOX(configure_vbox), pref##_frame, FALSE, FALSE, 0); \
+ pref##_vbox = gtk_vbox_new(FALSE, 10); \
+ gtk_container_set_border_width(GTK_CONTAINER(pref##_vbox), 5); \
+ gtk_container_add(GTK_CONTAINER(pref##_frame), pref##_vbox); \
+ \
+ pref##_desc = gtk_label_new(label); \
+ \
+ gtk_label_set_line_wrap(GTK_LABEL(pref##_desc), TRUE); \
+ gtk_label_set_justify(GTK_LABEL(pref##_desc), GTK_JUSTIFY_LEFT); \
+ gtk_misc_set_alignment(GTK_MISC(pref##_desc), 0, 0.5); \
+ gtk_box_pack_start(GTK_BOX(pref##_vbox), pref##_desc, FALSE, FALSE, 0); \
+ gtk_widget_show(pref##_desc); \
+ \
+ pref##_hbox = gtk_hbox_new(FALSE, 5); \
+ gtk_box_pack_start(GTK_BOX(pref##_vbox), pref##_hbox, FALSE, FALSE, 0); \
+ \
+ pref##_button = gtk_check_button_new_with_label(descr); \
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pref##_button), use_##pref); \
+ gtk_box_pack_start(GTK_BOX(pref##_hbox), pref##_button, FALSE, FALSE, 0); \
+ \
+ gtk_widget_show(pref##_frame); \
+ gtk_widget_show(pref##_vbox); \
+ gtk_widget_show(pref##_button); \
+ gtk_widget_show(pref##_hbox);
+
+void configure(void)
+{
+ GtkWidget *configure_vbox;
+ GtkWidget *xidle_hbox, *xidle_vbox, *xidle_frame, *xidle_desc;
+ GtkWidget *configure_bbox, *configure_ok, *configure_cancel;
+
+ if (configure_win)
+ return;
+
+ read_config();
+
+ configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect(GTK_OBJECT(configure_win), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed), &configure_win);
+ gtk_window_set_title(GTK_WINDOW(configure_win), "IMMS Configuration");
+
+ gtk_container_set_border_width(GTK_CONTAINER(configure_win), 10);
+
+ configure_vbox = gtk_vbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(configure_win), configure_vbox);
+
+ ADD_CONFIG_CHECKBOX(xidle, "Idleness",
+#ifdef BMP
+ "Disable this option if you use BEEP on a dedicated machine",
+#elif AUDACIOUS
+ "Disable this option if you use Audacious on a dedicated machine",
+#endif
+ "Use X idleness statistics");
+
+ /* Buttons */
+ configure_bbox = gtk_hbutton_box_new();
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(configure_bbox), GTK_BUTTONBOX_END);
+ gtk_button_box_set_spacing(GTK_BUTTON_BOX(configure_bbox), 5);
+ gtk_box_pack_start(GTK_BOX(configure_vbox), configure_bbox, FALSE, FALSE, 0);
+
+ configure_ok = gtk_button_new_with_label("Ok");
+ gtk_signal_connect(GTK_OBJECT(configure_ok), "clicked",
+ GTK_SIGNAL_FUNC(configure_ok_cb), NULL);
+ GTK_WIDGET_SET_FLAGS(configure_ok, GTK_CAN_DEFAULT);
+ gtk_box_pack_start(GTK_BOX(configure_bbox), configure_ok, TRUE, TRUE, 0);
+ gtk_widget_show(configure_ok);
+ gtk_widget_grab_default(configure_ok);
+
+ configure_cancel = gtk_button_new_with_label("Cancel");
+ gtk_signal_connect_object(GTK_OBJECT(configure_cancel), "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(configure_win));
+ GTK_WIDGET_SET_FLAGS(configure_cancel, GTK_CAN_DEFAULT);
+ gtk_box_pack_start(GTK_BOX(configure_bbox), configure_cancel, TRUE, TRUE, 0);
+ gtk_widget_show(configure_cancel);
+ gtk_widget_show(configure_bbox);
+ gtk_widget_show(configure_vbox);
+ gtk_widget_show(configure_win);
+}
+
+void about(void)
+{
+ if (about_win)
+ return;
+
+ about_win =
+#ifdef AUDACIOUS
+ audacious_info_dialog(
+#else
+ xmms_show_message(
+#endif
+ "About IMMS",
+ PACKAGE_STRING "\n\n"
+ "Intelligent Multimedia Management System" "\n\n"
+ "IMMS is an intelligent playlist plug-in for BPM" "\n"
+ "that tracks your listening patterns" "\n"
+ "and dynamically adapts to your taste." "\n\n"
+ "It is incredibly unobtrusive and easy to use" "\n"
+ "as it requires no direct user interaction." "\n\n"
+ "For more information please visit" "\n"
+ "http://www.luminal.org/wiki/index.php/IMMS" "\n\n"
+ "Written by" "\n"
+ "Michael \"mag\" Grigoriev <mag@luminal.org>",
+ "Dismiss", FALSE, NULL, NULL);
+
+ gtk_signal_connect(GTK_OBJECT(about_win), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed), &about_win);
+}
Index: imms-3.1.0-rc4/clients/audacious/rules.mk
===================================================================
--- imms-3.1.0-rc4.orig/clients/audacious/rules.mk 2008-03-02 18:54:06.000000000 -0700
+++ imms-3.1.0-rc4/clients/audacious/rules.mk 2008-09-19 15:28:17.000000000 -0600
@@ -7,7 +7,7 @@ libaudaciousimms-LIBS = $(AUDACIOUSLDFLA
audaciousinterface-CPPFLAGS=$(AUDACIOUSCPPFLAGS)
audplugin-CPPFLAGS=$(AUDACIOUSCPPFLAGS)
-audaciousinterface.o: bmpinterface.c
+audaciousinterface.o: audaciousinterface.c
$(call compile, $(CC), $<, $@, $($*-CFLAGS) $(CFLAGS) $($*-CPPFLAGS) $(CPPFLAGS))
AUDACIOUSDESTDIR=""
Phew. And that's not all. When you build IMMS you need to have OBJDUMP=gobjdump if you're using the default binutils variant from MacPorts, and this patch:
rules.mk | 2 +-
vars.mk | 6 +++---
vars.mk.in | 1 +
3 files changed, 5 insertions(+), 4 deletions(-)
Index: imms-3.1.0-rc4/rules.mk
===================================================================
--- imms-3.1.0-rc4.orig/rules.mk 2008-09-19 08:49:43.000000000 -0600
+++ imms-3.1.0-rc4/rules.mk 2008-09-19 16:17:33.000000000 -0600
@@ -19,7 +19,7 @@ link = $(CXX) $(filter-out %.a,$1) $(fil
-shared -Wl,-z,defs,-soname,$@ -o $@
%-data.o: %
- objcopy -I binary -O $(OBJCOPYTARGET) -B $(OBJCOPYARCH) --rename-section .data=.rodata,alloc,load,readonly,data,contents $< $@
+ $(OBJCOPY) -I binary -O $(OBJCOPYTARGET) -B $(OBJCOPYARCH) --rename-section .data=.rodata,alloc,load,readonly,data,contents $< $@
# macros that expand to the object files in the given directories
objects=$(sort $(notdir $(foreach type,c cc,$(call objects_$(type),$1))))
Index: imms-3.1.0-rc4/vars.mk
===================================================================
--- imms-3.1.0-rc4.orig/vars.mk 2008-09-19 09:03:05.000000000 -0600
+++ imms-3.1.0-rc4/vars.mk 2008-09-19 15:07:44.000000000 -0600
@@ -5,8 +5,8 @@ INSTALL = /opt/local/bin/ginstall -c
prefix = /usr
PREFIX = $(prefix)
OBJCOPY = gobjcopy
-OBJCOPYTARGET =
-OBJCOPYARCH =
+OBJCOPYTARGET = mach-o-le
+OBJCOPYARCH = i386
exec_prefix = ${prefix}
bindir = ${exec_prefix}/bin
datadir = ${prefix}/share
@@ -15,7 +15,7 @@ VPATH = ../immscore:../analyzer:../model
ARFLAGS = rs
SHELL = bash
-PLUGINS = libxmmsimms.so
+PLUGINS = libxmmsimms.so libaudaciousimms.so
OPTIONAL = immsremote analyzer
GLIB2CPPFLAGS=`pkg-config glib-2.0 --cflags`
Index: imms-3.1.0-rc4/vars.mk.in
===================================================================
--- imms-3.1.0-rc4.orig/vars.mk.in 2008-03-02 18:54:06.000000000 -0700
+++ imms-3.1.0-rc4/vars.mk.in 2008-09-19 16:17:24.000000000 -0600
@@ -4,6 +4,7 @@ VERSION = @PACKAGE_VERSION@
INSTALL = @INSTALL@
prefix = @prefix@
PREFIX = $(prefix)
+OBJCOPY = @OBJCOPY@
OBJCOPYTARGET = @OBJCOPYTARGET@
OBJCOPYARCH = @OBJCOPYARCH@
exec_prefix = @exec_prefix@
Finally, make install doesn't finish the job.
cp build/libaudaciousimms.so /usr/local/lib/General/imms.impl
Well I think that's all the information you need, though it may not go smoothly. Hopefully we can get this all worked into IMMS proper and the 3.1.0 release will just work. If you use linux give Audacious+IMMS a try—it's easy and painless. If you think Audacious is for sissies, learn about the queue and the jump feature and try out IMMS for a week or two before you pass final judgement.
Oh, two final notes: Installing Torch can be a real pain and Audacious keyboard shortcuts don't work well with the gtk2 +quartz variant in MacPorts, so you want to stick with X11 gtk2. Oh, and though Audacious has a Last.fm plugin I haven't yet been able to figure out how to get it to stay enabled.
Touch Typing
Steve Yegge has posted an funny, irreverent, and above all excellent argument for touch typing. I highly recommend it even if you do touch type.
I am downright flabbergasted by some of the comments though. There are hunt-and-peck folks defending their inability to touch type as lifestyle choice based on the belief that they will get RSI. People justifying typing slow because it saves them from wasting time chatting or writing long emails. There are some interesting claims from 2–4 finger typists that they can type without looking at 70wpm (this is certainly possible), and choosing not to learn to touch type the "right way" because it will give them RSI (this is certainly ludicrous).
Typing is a vital skill if you work in IT, especially programming. Of this there is no doubt, rationalizing strangers aside. I simply cannot imagine being stuck typing at 10wpm or less. It would be like being stuck behind a pair of tractors on the freeway going 20 mph. For the rest of your life.
Last I checked I type about 65 wpm on average. I could probably go faster, but I never have felt the need. I can type as fast as I think when programming. If I were a stream-of-consciousness novelist or a secretary, I could probably make use of a faster typing speed. As it is, 60–70wpm seems to be a sweet spot for me.
I'd like to discuss the ridiculous RSI claims. Yes, if you type all day without breaks you can get RSI. There are certain things you can do to mitigate or exacerbate this for a given amount of typing and typing speed. If you tried to go lightning fast all the time you might hasten the onset of RSI. But I argue that the absolute worst thing you can do if you're afraid of RSI is to not touch type. RSI means Repetitive Stress Injury, from repetitively performing certain motions until your body starts to break down. Smaller more relaxed motions are less stressful on your body than large stiff motions. If you touch type well, your hands are relaxed, your fingers float over the keys, and movement is minimal. Of course you still need to take care—take breaks, spend some time thinking without typing or drawing pictures on paper, proper nutrition, etc. But the biggest thing you can do to prevent RSI is to have proper form. And maybe learn dvorak (I still use qwerty because I find sysadmin and programming to be tedious with dvorak, but I don't spend most of my time actually typing).
On the other hand, if you hunt and peck 24/7 guess how much more movement—repetitive movement—your body is enduring? Ever heard of tennis elbow? RSI isn't the exclusive privilege of touch typists. If you type slow enough that you can't possible get RSI, you are irrelevant. If you type fast enough to be productive but don't have good form, you are setting yourself up for RSI. If you're RSI-prone or just paranoid, go learn dvorak now or find a job that doesn't require much typing.
I'd add to Steve's exhortation to learn to touch type, that if you do touch type but you feel your form is off, you have low accuracy, or you feel that your fingers are stiff, do some conscientious practice. Focus on accuracy and relaxation first, then speed. Enhancing your typing skills is a great benefit if you spend a lot of time typing, although learning to touch type in the first place is obviously a much bigger payoff.
Let's continue to learn from musicians: correct form (including relaxed posture and keep those wrists off the keyboard/desk), accuracy, then speed.
Hipster Redux
I've talked about the Hipster PDA a few times. I finally stabilized on a system that works for me. I've been using it steadily for months with no major changes now, so I thought I'd share with you.
My brief foray into the hipmod was fun, but too restrictive and small in the end. I understand others enjoy it though, so I'm glad I did it.
I find the classic hipster with a few modifications works best. My biggest beef with the original hipster is that it falls apart and it's not very user-friendly. That binder clip had to go. So I got some binding rings (½" I think, but the exact size isn't critical) and use a standard 3-hole punch to punch 2 holes in the index cards, and bind it with 2 rings. This makes a more book-like planner, which nicely folds over on itself.
Now, those rings can be pesky to open and close so I decided not to. I snip a little cut from the edge of the cards I want to be removeable to the holes. They stay in but will come right out and go right in without struggle.
I also like to print some forms (as you've seen). These I just print on regular paper and trim to size with a guillotine then hole punch (no snips, that works best on cardstock).
I made front and back covers out of a cereal box and duct tape, and even a pen holder out of duct tape. I'll post a picture soon so you can see.
My planner consists of a few reference pages I printed out (including a circle of fifths, a few airport kneeboards, performance data for my favorite planes, and morse code… anything you can find a PDF for.), my weekly calendar/todo list pages, and a bunch of index cards that I use for notes, moments of inspiration, or whatever else they come in handy for. Oh, and a paperclip to mark the current week. I only have to reprint/refill the weekly pages about once every 3 months or so.
For printing things, I wrote a script that automates some of what I mentioned in previous posts.
Use a balloon to estimate RV
So it's been awhile since I estimated my residual lung volume (RV), and I figured it was time to do it again.
I'm a big guy, so my lungs hold a lot of air. When you're blowing all your air into containers in the bathtub, and you're ⅔ or more exhaled, is not the best time for pausing to move your straw to another container—or worse, refilling the container. This time I decided to use a balloon.
I took a deep breath, exhaled maxmially into the balloon, then blew the rest into the container through a straw. (Wait, did he just say "the rest" after "maximally exhaled"?) I heard that. Yes, you can't exhale all of your air because the pressure in the balloon is higher than atmospheric pressure. In my case, I had another 400ml of air.
Then I emptied the air out of the balloon into the container. This is easy and leisurely once you figure out the trick, but it can seem next to impossible at first. Hint: don't try to submerge the balloon. If you grab the lip of the balloon mouth only, and avoid pinching the neck, you can control the air flow very well. There, I had measured my vital lung capacity (VC).
It worked great, and compared with the last circus event when I measured VC it was much easier.
Now I had to figure out how to get from VC to RV. The clown who wrote http://hans.fugal.net/density kind of left this step vague. I've remedied that and added a page to my spreadsheet. For the curious, my RV is up from 2.0 liters to 2.2 liters, and a total lung capacity of 8.2 liters.
%BF Nomogram
Remember that system I came up with for calculating body fat percentage using a gallon jug in a swimming pool? I always let the computer do the calculations for me—I have a little script that I run that updates my weight graph. But not everyone is as geeky as that, and formula is not that simple, and when you add units conversion in it gets downright hairy.
I finally figured out how to generate a nomogram. Now you have no excuses.
Token Bucket of Life
When it comes down to it, the secret of productivity is to just do it. In our line of work, it's not as simple as you're either chopping a tree down or you're not. So it's easy to get distracted on tangential or unrelated tasks and trains of thought. If I didn't know people personally who somehow manage to avoid this trap most of the time, I'd think it was impossible. For the rest of us, I present a nifty trick.
Grab two condiment bowls, shot glasses, rolls of tape, whatever. Now grab some glass "stones", some pebbles, some M&Ms, whatever. The former are buckets. The latter are tokens. Put all the tokens into bucket A.
Now for every hour you work (really), move a token from bucket A to bucket B. Do this every day for a week and keep a tally. This will show you how much time you are working and how much time you are squandering. It will be depressing. Don't let your boss see.
Now decide how much time you will permit yourself to squander. You might feel that should be 0, or maybe you feel you deserve an hour a day. No matter what you feel it should be, make a realistic goal at this point. It's just like physical excercise you know. So figure out the ratio between work time and play time. 4:1 makes the math convenient, so let's take that ratio. Now, for every hour you work you bring a token from A to B. It represents 4 quarter hours in bucket A, but only 1 quarter hour in bucket B. That is, you get to play 15 minutes for every token you have in B. Think of it as a bank account. If you don't got no tokens in the play bucket, you work. If you do, you might keep working because you're in the zone. But you might play, because you have the tokens to do so. So play, and play guilt free. The guilt-free recreation is as important as anything here. If you can't bring yourself to give yourself permission to play at work, then split it up between stuff you hate and stuff you enjoy. You do enjoy some aspect of your work, no?
This is just a slightly-modified token bucket scheme, like that used in network shaping (e.g. Quality of Service). When I first came up with it, I was inspired by "token economics" which was suggested for potty training. When I had the system going for a day or two, and was working on a QoS presentation, it dawned on me that what I had here was a token bucket. That makes it all the more cool.
What good is it? I think it's an effective tool for a couple of reasons: it's simple, unobtrusive, and authoritative. It keeps you accountable, both to it and to yourself, and to anyone who looks on that knows what it means. It doesn't nag you, nor is it susceptible to your rationalizations. It's easy to reset or set aside when it doesn't apply (when a deadline looms and you don't have time to play at all). The only habit you need to get into is checking your account before playing. But if you fail to remember, you can always adjust the totals retroactively, in which case although you may have overdrawn you will still see the state of affairs, and have an opportunity for introspection.
Now if you'll excuse me, my play bucket just ran out.
Tuttle, OK
This email exchange is pretty amusing. The debate in the comments is fairly tiring, actually. You have the LOLs and the apologists, but nobody seems to take the middle road.
Here's my take: Jerry acted like an idiot. He should have called in IT. Johnny was mostly polite and very patient, but he made a mistake: he tried to reason with a panicking idiot.
If I were Johnny, here's what I hope I would have done. I would have gone along more or less like Johnny did until the FBI threat came. That would have been my signal that I'm dealing with an irrational person and I would have then said something like "Neither I nor CentOS has done anything to your server. I will not entertain any further correspondence unless it comes from your IT department." Inside I would be secretly hoping that he calls the FBI. I've always wanted to meet an FBI agent. We could go to lunch with an FBI IT guy and have a good laugh.
Older posts: 1 2