The Boston Diaries

The ongoing saga of a programmer who doesn't live in Boston, nor does he even like Boston, but yet named his weblog/journal “The Boston Diaries.”

Go figure.

Thursday, March 01, 2007

“… if you don't leave me alone, you're gonna have to send me home …”

For a bunch of people I know that need help throughout the day while at work: “I'm about to whip somebody's ass” by Ray, a minister who wanted to help his daughter get through the day (and Gregory, I think you could really do this justice at karaoke).


A little bizarre slice of life

“Could I ask a favor,” asked Spring. “I need you to pick me up.” She had called earlier, saying her van was overheating and that she would be a bit late in getting home. Apparently her quest in getting coolant ended in failure. “I'm at a gas station on Atlantic just west of I-95.”

“Okay, I'll be there in a bit.”

Half an hour later, I arrive at the gas station to find Spring sitting next to a young man. “This is Josh,” said Spring, “and since we're doing all this driving anyway, could we drop him off at the West Palm Beach Tri-Rail station?”

“Sure,” I said. “I don't mind.” Josh and Spring got into the car and we drove off.

During the drive up to the West Palm Beach Tri-Rail station Josh was very quiet, only answering direct questions and not offering much else in the way of conversation. After dropping him off I asked Spring what exactly his story was, since he didn't really volunteer anything on the drive up, and she said he had walked from Key West to that gas station over the past three weeks, and that he was getting a bus ticket (courtesy of a friend) at the West Palm Beach Tri-Rail station for a cross-country trip to Sacramento, California for his mother's funeral.

Oh.

Okay then.

And that's all the details we have. No indication of how he ended up in Key West (apparently he's from Sacramento). Nor how he ended up sans transportation other than his two feet and other than that … not much else to say.

Friday, March 02, 2007

Two things

Two things, tangentially related, but enough to push me into a bad mood (it was the inability to log into a server that pushed me into a really foul mood, but I'm better now).

Thing the First: I'm driving about and I end up behind a school bus dumping kids off. Annoying, but a normal part of traffic at that time of day. No, what set me off was the line of cars along the side of the road waiting to pick up the kids. What? Can't let Brandyn and Heathyr walk a two blocks home, can we? (And for the record, the neighborhood was far from being South Central Los Angeles) Can't even be bothered to drive the few miles to the school to pick up Brandyn and Heathyr either. For those parents, I would love to give their kids their very own lawn roller coaster.

Have fun, kids.

Thing the Second: From a ticket in our trouble ticket system, “Is it possible foward a copy of an employees mail to another account temporarily without their knowledge?” What's wrong? Don't trust your employees? Need to watch over them like little kids? Perhaps you should give them their own lawn roller coaster too? But don't expect your employees to trust you much. (To be fair, I don't know the reason behind the request and there could very well be a legitimate reason, like a police investigation behind this, but this is my first reaction to this).


So what exactly is the point of dynamic libraries if the applications behave as if statically compiled? Could it be that the OpenSSH boys are too paranoid? Or just perpetuating a very cruel joke at our expense?

A few days ago Smirk received an updated security scan of a customer's box and they didn't like our version of OpenSSL (it being more than 20 minutes old, you see). Yesterday Smirk called and told me to update OpenSSL with the latest buggy version instead of the buggy version 30 minutes old.

In theory, it's easy enough. I mean, the whole point of shared libraries is that you can update just the library without having to recompile and relink a bazillion applications. So I download the latest version, compile and install. In checking over the programs that use SSL, it seemed just easier to reboot the box than to restart the bazillion processes (sorry Pinocchio). In theory, everything should just work.

In theory, there is no difference between theory and practice. In practice, there is.

Everthing came back up, except OpenSSH.

Sigh.

So today, at the office, I check into the problem. OpenSSH basically said, “Sorry, you're trying to use a version I wasnt' compiled against. Even though I'm dynamically linked against that library, I'm refusing to run. So Nyah!”

XXXXXXX piece of XXXX do as you're XXXXXXX told you XXXXXXXXXXXXX XXXXXXXXXX!

I was better.

Multiple attempts at recompiling later, it worked. Although I think I hurt my foot in the process …

[And I managed to botch the posting of this entry. Tells you how my day has been … ]

[TWICE! This got botched TWICE! And when I attempted to fix the problem, I ran into Linux's schizophrenic approach to the Backspace key. Hey Linus! It's XXXXXXX Ctrl-H you moron! ASCII value of 8! Eight! EIGHT! Not the XXXXXXX DEL character! BACKSPACE!

Bad Linus! No cookie for you!

And to further continue my downward spiral I clicked somewhere on Firefox and I lost the nagivation toolbar.

Hate hate hate hate hate hate hate.]


Speechless

Finally, a toy that invites children to explore the nature of cruelty. In fact, Electronic Test Tube Aliens ($15) are either the most cynical and ill-conceived toys on the market, or the world's first truly existential toy. The story is simple: There's an alien invasion on, and you get to be a collaborator by taking care of a Wi-Fi-enabled, battery-powered alien adoptee. Three of the aliens are good and three are evil; whether yours is good or evil has no bearing on how your creature will behave, since these test-tube babies can't fight each other or really do anything. Except die. In fact, that's their specialty.

Via Postcards from the Bleeding Edge, Test Tube Aliens: Gadget of the Week

You know … this just … fifteen dollars … words … fail me.

Next thing you'll know, people will be selling virtual 70s style porn beds … oh wait a second …

Saturday, March 03, 2007

More Wiki than a Wiki

I've played around with several WikiWikiWebs (like TwikiK, which I find somewhat clunky, and UseModWiki, which I find okay) but none so far has impressed me more than TiddlyWiki, which has to be the easiest wiki to install—just one file and no web server required.

On the downside, it's just one file and I mean, everything is stored in that one file. It makes the editing of content pretty sweet and rather fast, but I'm guessing that as more content is added, the slower it gets since it all runs in the browser. An interesting twist might be to update content on the server using AJAX, although I'll have to check to see if it's already been done.

Sunday, March 04, 2007

First impressions of TiddlyWiki

I was initially very impressed with TiddlyWiki, but the more I play around with it, and think on how it works, the less inclined I am to actually use it.

I have a directory on my home computer called writings, which contains a ton of files related to writing. Ideas, notes and several attempts at novels (mostly attempted during National Novel Writing Month) litter the directory, making about 16 megabytes of stuff just sitting there, waiting for me to do something with it all (hmmm … a recipes file—interesting).

Sixteen megabytes. That's a large amount of text to store in a single file (aside from the issue of actually getting it all into any type of Wiki to begin with), much less work with a file that large. I did, however, import (using cut-n-paste) one of the files, ideas into TiddlyWiki to get an idea of what it would be like.

I'm resistant. I find it just as easy to use simple text files as it is to use TiddlyWiki, but with the text files, I can use any computer with Internet access and an ssh client. With TiddlyWiki, I would have to copy the file to whereever I am and afterwards, make sure to copy it back to my home computer (and yes, that is an issue with me).

There's also the sad fact that the base TiddlyWiki is over 220,000 bytes of JavaScript code and requires a 28MB “helper app” to execute whereas the editor I use is about 174,000 bytes, has more features (like the editing keys I have on my keyboard actually usable for their intended purposes), and doesn't require a multimegabyte “helper app” to execute (unless you count the operating system as a “helper app”).

I'm still looking for the perfect editing system.

Monday, March 05, 2007

Paralysis in the sleep

I think I finally figured out what triggers my sleep paralysis attacksnaps.

I ended up taking a nap this evening (combination of a really screwed up sleeping schedule and sleep depravation since I had to get up early today since P. is out of town), and I intended to only sleep for maybe an hour or so, but I slept longer than I expected. Durring the nap, I experienced an attack of sleep paralysis. It wasn't as bad as some of my previous attacks (now that I know what's going on, the process isn't nearly as frightening) but it still quite annoying and it seemingly takes forever to snap out of it.

But in thinking over my past attacks, they have all (to my recollection) happened when napping, or rather, napping longer than I wanted to nap.

Tuesday, March 06, 2007

“… in other news, pigs were seen flying by … ”

Since I no longer have to work at The Office, I brought home my workstation with the intent of using it to replace my aging home system linus.

processor	: 0
cpu		: 486
model		: Am5x86-WB
vendor_id	: AuthenticAMD
stepping	: E
fdiv_bug	: no
hlt_bug		: no
f00f_bug	: no
fpu		: yes
fpu_exception	: yes
cpuid		: yes
wp		: yes
flags		: fpu
bogomips	: 66.56

Yes, it's probably ten to twelve years old by now (in fact, I'm using it right now to write this very entry), and while still usable, it is getting a bit long in the tooth and now is as good a time as any to replace it.

The intent was to use my workstation to replace two computers (the aformentioned linus and my firewall, janet, a 33MHz 486) and a switch, since I have this four-port ethernet card.

After mucking about for a few hours today (and ripping my favorite shirt in the process—sigh), I've come to the conclusion that I can't replace the switch, since the four-port ethernet card doesn't work with modern Linux systems (in a weird twist of fate, it would probably work in the current linus since it's still running Linux 2.0.39—to say that the drivers for this card haven't been updated is an understatement—the card itself is over 13 years old). I was, however, able to munge up a 2GHz system with three network cards and an additional IDE controller (the intent here is to just dump the drives in linus into the new system, plus some other drives from some other computers around the house; I think I'll end up with six drives in the system).

While I'm not finished yet, I did however take the old drive out of tower, my first webserver and slapped it into my new computer. Odd seeing the state of the site from four years ago (back when Mark still had a blog), and hey, I can always use an additional 17G of space. Lord knows I paid enough for it.

Wednesday, March 07, 2007

“Good, bad, I'm the one with the compiler.”

I've been doing some heavy programming lately, dealing with schlepping bits into and out of QuickBooks (which I'll name Project “Pacino” which is related to the actual name of the project) and my part so far is with getting data into and out of MySQL.

The first pass involved writing an extention to MySQL to run an external program from a trigger. One guy, however, kept popping up on the various threads advising against this:

I always recommend against doing things like this. Calling an external processes from a trigger or UDF is very difficult to get right, and it is very easy to cause serious problems with your application.

Catch-22 of the Active Database

Well … good, bad, I'm the guy with the compiler. And Bill Karwin's advice of polling the database doesn't sit well with me. Heck, polling in general doesn't sit well with me (“Are we there yet?” “Are we there yet?” “Are we there yet?” “Are we there yet?” “Are we there yet?”). But I can see why Bill is cautious, and I wrote the code with his problems in mind.

It works, but there are cases when the notification doesn't go through (the program we invoke collects the updated record to update another, non-MySQL database (else we'd just use MySQL replication) and if we can't update the other database, the notification goes unnoticed). So it was back the drawing board for another approach. This time, the approach is for MySQL to log the changes to another table and to notify a daemon of the update. The daemon then pulls the changes from the table MySQL updated and does whatever with them. Since MySQL also logs the changes, if the daemon isn't running, the changes just pile up in a queue for later processing.

Now, as I'm working on attempt two, I did get permission to release the code for calling an external program from MySQL. The code is pretty simple and while it does work, it's quite simple (only MySQL strings are supported for instance) and could hammer a server pretty hard, depending upon the size of the update. It's not public yet, but if anyone were interested in the code, I can give it out …

Thursday, March 08, 2007

Scaling daemons

I'm still deep in programming.

So now I'm writing a daemon.

The first problem was getting MySQL to contact the daemon, and I forgot—I'm working under Unix, and interprocess communications suck under Unix. You have pipes, but they only work between processes that have a common ancestor. You can get around that problem by using named pipes, which get around the common ancestor, but there's still a limit to the amount of data that can be in the pipe, and if one side isn't listening (say, the daemon) then the other side is blocked. No good.

Oh, I could try using message queues. But it too, has problems—no automatic reclaimation of system resources when one side (or both!) crash. They're not identified by name and there are no tools to list the exiting message queues or delete them! And they can't be used with the multiplexing I/O API (select() or poll(), which I'll probably be using if I'm dealing with tons of connections).

The same problems exist for shared memory by the way, plus a whole slew of synchronization problems between unrelated processes, which probably mandates the use of semaphores, which again, have similar problems with message queues and shared memory.

Told you interprocess communication under Unix sucks.

Leaving sockets. Since they use regular file descriptors, they work with the multiplexed I/O API, but I hate using select(), since you end up scanning through arrays. The code that uses select() typically looks like:

while(1)
{
  FD_ZERO(&list);
  
  for (i = 0 ; i < files_count ; i++)
    FD_SET(files[i],&list);
  
  rc = select(FD_SETSIZE,&list,NULL,NULL,NULL);
  
  if (rc < 0)	/* select() returned an error */
  {
    handle_error(errno);
    continue;
  }
  else if (rc > 0)	/* we got some */
  {
    for (i = 0 ; i < files_count ; i++)
    {
      if (FD_ISSET(files[i],&list)
      {
        if (files[i] == listen_socket)
        {
          len = sizeof(remote_addr);
          connection = accept(listen_socket,&remote_addr,&len);
          
          /*----------------------------------
          ; oh great, we need to add this to the end
          ; of the files array, but that readjusts the 
          ; file_count variable ... buyer beware ... 
          ;-------------------------------------*/
          
          add_to_list(files,connection);
        }
        
        /*-----------------------------------
        ; oh bloody hell, we're listening to 
        ; MySQL as well ... sigh.
        ;----------------------------------*/
        
        else if (files[i] == mysql_connection)
        {
          handle_that_mess(mysql_connection);
        }
        
        /*---------------------------------------
        ; otherwise it's a connection from outside
        ;--------------------------------------*/
        
        else
        {
          /*-----------------------------------
	  ; oh man, we need to find the data
          ; associated with this connection, so
          ; that means another scan of some other
          ; list ... Aiiiiieeeeeeeeeeeeeeee!

I've been down this route before, and it resulted in some of the most convoluted code I've ever written. And looking at poll(), it doesn't appear much better.

I could get around using select() or poll() by creating a multithreaded or multiprocess application, but that's a whole new can of worms I'm opening up (deadlocks or race conditions anyone?) in addition to the problems I mentioned above about interprocess communication.

In looking around for a usable solution, I came across epoll, which is a new multiplexing I/O API in the newer Linux kernels. Reading over the documentation, it looks like you add file descriptors to an “epoll queue” (which itself is a file descriptor), then you call epoll_wait() which returns an array of file descriptors that are ready for reading or writing! It saves scanning through an entire list of file descriptors continuously asking “do you have data?”

What sold me was looking at the definition of the event structure:

typedef union epoll_data {
	void *ptr;
	int   fd;
	__uint32_t u32;
	__uint64_t u64;
} epoll_data_t;

struct epoll_event {
	__uint32_t events; /* Epoll events */
	epoll_data_t data; /* User data variable */
};

User data variable?

I get a pointer?

Associated with a file descriptor?

No way?!

Define a few structures with function pointers, and boom! The main loop now looks like:

void mainloop(int queue)
{
  struct epoll_event list[10];
  int                events;
  int                i;
  struct foo         data;

  while(1)
  {
    events = epoll_wait(queue,list,10,TIMEOUT);
    if (events < 0)
      continue;	/* error, but we ignore for now */
    for (i = 0 ; i < events ; i++)
    {
      data = list[i].data.ptr;
      (*data->fn)(&list[i]);	/* call our function */
    }
  }
}

Man, this now becomes easy. No more having to constantly check file descriptors or maintaining lists of file descriptors. I'm in heaven with this stuff. Even better that this method scales beautifully.

Friday, March 09, 2007

Cheating your way to a robust daemon

Programs written in Erlang have minimal (if any) error checking. The intent by the designers of Erlang is for buggy Erlang code to crash early and hard. No defensive programming for these guys, which seems odd given that Erlang is used primarily in phone switches, which have ridiculous uptime and reliability requirements, but not really.

You see, most Erlang programs are watched over by an even simpler program that simply waits for a crashing program and restarts it automatically, while logging the incident.

It's a pretty neat concept, and for the daemon I'm writing, I've done just that.

Well, I don't actually have a separate process watching, because one isn't needed. No, what I've done is catch a few signals that end up killing the program (like SIGSEGV) and instead of terminating the program, restarting it.

extern char **environ;
char         *global_argv[];

int main(int argc,char *argv[])
{
  /*----------------------------------
  ; save our command line.  I do this
  ; so *if* we re-exec ourselves, we
  ; re-exec ourselves as we were initially
  ; exec'ed.
  ;----------------------------------*/

  global_argv = argv;

  /*--------------------------------------
  ; Wrote my own signal() function that ensures
  ; reliable signal semantics (via W. Richard Stevens'
  ; Advanced Programming in the UNIX Environment).
  ; 
  ; Here, I'm capturing those signals that
  ; may be the result of bad programming and
  ; end up generating a core file, and catching
  ; those to restart the program.
  ;----------------------------------------*/

  set_signal(SIGSEGV,crash_recovery);
  set_signal(SIGBUS, crash_recovery);
  set_signal(SIGFPE, crash_recovery);

  /* ... */

  return(EXIT_SUCCESS);
}

void crash_recovery(int sig)
{
  syslog(LOG_ERR,"received sig %d---restarting",sig);

  /*--------------------------------------------
  ; The signal we're handling may very well be
  ; blocked, which will persist across the execve()
  ; call.  This results in the first crash being
  ; caught, but not subsequent crashes.  By unblocking
  ; all signals, we assue we can catch further
  ; crashes.
  ;----------------------------------------------*/

  sigfillset(&sigset);
  sigprocmask(SIG_UNBLOCK,&sigset,NULL);

  /*---------------------------------------
  ; close all the files, but keep the standard
  ; STDIN, STDOUT and STDERR open.  Sure, we 
  ; loose any connections, but we'll loose them
  ; anyway if the program were to go away.  
  ;----------------------------------------*/

  for (i = 3 ; (i < OPEN_MAX) && (close(i) == 0) ; i++)
    ;

  /*---------------------------------------
  ; restart myself.
  ;------------------------------------*/

  execve(global_argv[0],global_argv,environ);

  /*----------------------------------
  ; well ... if we get here, we're screwed
  ; so might as well give up.
  ;------------------------------------*/

  _exit(EXIT_FAILURE);
}

This could be a very bad idea but I'll see how well it works out.

Saturday, March 10, 2007

Page views

I came across Project Wonderful from Eric Burns. I read up on its advertising scheme and found it rather compelling. I have web space to sell ads, and given that Google's AdSense has been a disappointment, I thought I would sign up and give Project Wonderful a try.

I'll have to wait a while.

In trying to keep the system from imploding under heavy traffic, they're slowly expanding and I have to sign up for an invite to display their advertising. On the form asking for the invite, they asked for an average number of page views per day my site gets.

I don't have a package like AWStats, Webalizer or Analog installed (being too lazy to install and configure them). Instead, I have some home brewed programs that allow me to trawl through the log files manually (which for me gives me a better feel for what's going on anyway). I figured just searching for screen.css would give a good indication of page views (since it's used to render a page view), so I extracted the logs from a few days ago and checked.

Thirty-seven page views.

That's it?

I tried another day.

Thirty-seven.

I went back to the January logs.

Thirty-seven.

Thirty-eight.

Sixty-four.

Thirty-eight.

Oh.

That might explain the rather lackluster results from Google's AdSense.

But in going through the logs, I did come across the following:

Plus other feed readers that don't report the number of readers (about another 70) so my readership is up there, but primarily through outlets other than here.

Well then … perhaps I have to rethink the whole advertising thing then.


Whose bright idea was that design?

If anyone is wondering why: PHP's strpos() returns “false” when the second string argument does not occur as a substring of the first argument, and returns 0 when the second string argument occurs at position 0 of the first string argument. Thus, strpos( “/admin”, “/admin” ) returns 0, but strpos( “Cabbage/admin”, “/admin” ) will return a positive integer.

You're supposed to test the return value explicitly: “if( strpos( $a, $b ) !== false)”, but it only says that like five times in giant red letters on the manual page (http://us2.php.net/strpos) so it's easy to see how someone could miss it.

Re: Cabbage Based Authentication

Besides being reason #3.1415926 for hating PHP, this is a further example of my dislike for dynamically typed languages (and muddled thinking). What we have here is a function that returns a positive integer if we find one string within another, but a boolean otherwise. This mixing of return types is futher compounded by the fact that in PHP, an integer value of 0 is also treated as the boolean “false” value.

So let's not fix strpos() to return something sane, like -1 for “string not found,” let's instead extend the langauge with a silly “boolean only comparison” to fix this particular problem.

I would really love to know what Rasmus Lerdorf was smoking


Science in action II

Bunny received one of those forwarded emails that detailed a bunch of stupid cell phone tricks one could try. Among the stupid cell phone tricks (like dialing “*#06#” to get the phone's serial number, or dialing 800-FREE-411 (800-373-3411) for free dialing assistance) was one really silly bit:

Subject: Have you locked your keys in the car?

If your car has a remote keyless entry device this may come in handy someday. If you lock your keys in the car and your spare keys and spare remote keyless device are at home, call someone at home from your cell phone, hold your cell phone about a foot from your car door, and have the person at your home hold your spare remote keyless device up to the phone and tell them to press the unlock button. Presto, your car will unlock. Saves someone from having to drive your keys to you. Distance is no object. You could be hundreds of miles away. All you have to do is reach someone who has the other “remote” for your car and you will be able to unlock the doors or the trunk (where it might be a good idea to keep a spare set of keys in case you lose yours).

Another remote frob myth that sounded way too silly to me.

So of course I had to try it.

I gave Bunny my keys and went outside to stand next to my car. Then I called her. “Help, help, I locked myself out of my car,” I said.

“Okay,” she said. “Don't panic. I have your spare set of keys right here in the house. Hold your phone about a foot away from the car.”

I did that. Nothing.

We tried again.

Nothing.

Bunny then suggested using her landline to call me. Perhaps it would give a better signal.

Nope.

I suspect it doesn't work since my keyless frob works on radio waves, not an actual audible sound.

[Busted]

Sunday, March 11, 2007

Home alone (with a few cats though)

Spring and Wlofie are away for the week, gone camping at Gulf Wars, an SCA event.

Me? I'm not the camping type; roughing it is a hotel room with spotty Internet access.

Here's hoping they have fun.


As you wish.

Computers excel at following instructions to the letter.

Programmers don't quite excell at giving instructions to the computer.

Case in point: the daemon I'm working on. Through testing, I found that the automatic restarting wasn't working in all cases. If the program ran in the foreground, it would restart properly upon a crash. If it started up at an actual daemon though, it would fail. It took me a few hours to debug the problem, primarily because for this problem, I couldn't use gdb (the Unix debugger) for a few reasons:

  1. going into daemon mode creates a new process, which isn't the one that gdb starts debugging. To get around that problem, you can start the program up, and then attach gdb to the running process. That still leaves
  2. gdb will catch the segfault for you, instead of passing it on to the program. There very well may be a way to pass it on, but I'm not sure how well gdb handles signal handlers.

Painful as it is, the lack of a debugger can be worked around. And before I reveal the actual problem, here's the relevant code (sans error checking, as that only clutters things up):

int main(int argc,char *argv[])
{
  global_argv = argv;	/* save argument list for later restarting */

  if (gf_run_in_foreground == 0) 
    daemon_init();

  signal(SIGSEGV,crash_recovery);
  
  /* rest of program */
}

void daemon_init(void)
{
  pid_t pid;

  pid = fork();
  if (pid == 0)		/* parent exits, child process continues on */
    exit(EXIT_SUCCESS);

  chdir("/tmp");	/* safe place to execute from */
  setsid();		/* become a session leader */
  close(STDERR_FILENO);	/* close these, we don't need them */
  close(STDOUT_FILENO);
  close(STDIN_FILENO);
}

void crash_recovery(int sig)
{
  extern char **environ;
  sigse_t       sigset;

  syslog(LOG_ERR,"restarting program");

  /*---------------------------------
  ; unblock any blocked signals,
  ; including the one we're handling
  ;---------------------------------*/

  sigfillset(&sigset);
  sigprocmask(SIG_UNBLOCK,&sigset,NULL);

  /*---------------------------------
  ; restart ourselves.  If the call
  ; to execve() fails, there's not 
  ; much else to do but exit.
  ;---------------------------------*/

  execve(global_argv[0],global_argv,environ);
  _exit(EXIT_FAILURE);
}

Another bit of critical information: I would start the program thusly:

GenericUnixPrompt> ./obj/daemon

If you're good (say, the calibre of Mark) you'll see the problem. If not, don't worry—it took me a few hours. Here's a hint: Once I removed the call to chdir(), the code worked fine in daemon mode, and no, chdir() wasn't failing.

In fact, it didn't matter where I put the chdir() call, having it in there would cause the re-exec to fail when running in daemon mode.

The problem?

By changing directories, the relative path I was using to start the program was no longer valid when calling execve(), and of all the places where I could check the return code, that wasn't one of them. It didn't dawn on me (until thinking about it for a while after removing the call to chdir()) what the actual problem was.

Sheesh.

Here was the program, doing exactly what I told it to do, only I didn't realized what I was telling it to do wasn't what I thought I was telling it to do.

My brain hurts.

As a postscript to this, even if I were able to start the program under gdb, trace into the new process created, pass on the segfault to the signal handler, it wouldn't reveal the problem because gdb uses the full path to the program when running it, thus masking the real problem.

Lovely, huh?

Monday, March 12, 2007

Steampunk Star Wars

This is for Jeff Cuscutis, who likes this sort of thing:

Massive Solar-Orbiting Electro-Mechanical Analytic Engine, Mark 6

This enormous Imperial space station, the size of a small moon or asteroid, is in fact an immense analytic engine, a device capable of making millions of calculations every day. Inside is kilometer after kilometer of tubes and wheels, cranks and gears, all spinning and clacking, spitting out an endless series of numbers for the Imperials scientists to decipher.

Via kisrael.com, Eric's Terrible, Horrible, No Good, Very Bad Idea: steampunk star wars

And the accompanying pictures are cool too (secret message to Jeff: can I get a Phlogisticated Aether Torch?).


Premature optimization

“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.”

Donald Knuth

Since when did correct data typing in the production database become optimizations???

Comments on We'll Optimize Later

This is echoing a feeling I've had now for the past year or so—the phrase “premature optimization is the root of all evil” has been so drilled into programmers that it seems like no thought at all is being employed.

Technically speaking, writing code is “premature optimization.” Why bother even writing code when we can call upon the mighty powers of the lazy web to see if it's been written already. Or something close. Heck, it doesn't even have to be close, as long as it's code that can be adapted (just try to ignore the time factor when it takes longer to adapt code than it would have taken to write code from scratch, which may make a better impedance match to the rest of your code).

So remember, thinking about your code is a form of premature optimization.


Hammers and nails

Before I started at The Company, Smirk used a spread sheet to keep track of IP address allocations. It was easy to set up and edit and it worked for him. Besides, he has it running anyway to help manage the finances of The Company. So why not use it?

Then I took on the job of allocating IP addresses. I used (and still use) text files (one for each Class-C block we use). It was easy to set up and edit and it works for me. In fact, I use text files extensively to keep track of all sorts of things at The Office, from firewalls to managed power strips.

When P started, he set up Twiki as the company knowledge base. I don't know how easy it was to set up, but P seems to find it adequate to use and is currently a bit upset that he's the only one who bothers to update it. I personally don't find it that easy to use and consequently, I don't use it.

Personally, I'm picky about editors, and while I can't say I love joe, I am comfortable using it. But heck, I'd rather use Emacs to edit than the crap editor you get in your web browser du jour (and yes, that includes Firefox). That partly explains why I dislike the Twiki (there are other reasons), and don't even use my own web interface to post entries here (it's almost exclusively the email interface).

The problem here is, all three of us use different tools to manage certain types of information about The Company, and because of that, we don't have a true company wide information base that we can rely upon.

And no one has an idea of what we should use, because of how we all work.

Tuesday, March 13, 2007

Those ol' collaborative blues

The tone for today was cast in electronic stone when I wrote the following in a thread:

For me, it can't be purely web based, as I loathe editing text in a browser (really, the editing capabilities of a <TEXTAREA> sucks). It has to feel quick (it doesn't have to be quick) and it should be easy to create new nodes, notes, blobs or whatever. I would like the ability to customize the key bindings (Home goes to begining of a line, Ctrl-Home to the start of the document, etc).

Oh, and multiplatform (at a minimum, Linux and Mac OS). Given that, I would want hooks for loading and saving to throw the document into and out of some form of version control software (because I want the ability to edit the master copy reguardless of which computer I'm on, and yes, I do use multiple computers at multiple locations on a regular basis).

So far, nothing has beat logging into my home computer and using a text editor.

Me, in a thread on scheherazade in blue jeans—Clarification on mindmapping stuff

While the thread in question was about mind mapping software I see parallels with the current situation at work.

I think I have a handle on what I hate most about WikiWikiWebs: editing the pages. Each wiki has its own concept of markup (more or less) and it's markup that is supposedly easier to type than HTML. And certain typographical conventions are rather easier to use than HTML, like *asterisks* for strong emphasis or _underlines_ for plain emphasis.

Heck, mod_blog has a few things like that, for instance “-- -” for “&mdash;” (which makes a nice “—”) or even `<-- --="--">` (two backtics, which on most keyboards is in the upper left corner) gets translated to &ldquo; which gives the nice opening double quotes.

No, where it starts failing for me is in the structural markup. Weird rules like “lines that start with an asterisk denote an unordered list, to get nesting, nest the lines”

* one
* two
  * a
  * b
* three

Or was that “lines that start with an asterisk denote an unordered list, get nest nesting, add asterisks”

* one
* two
** a
** b
* three

And was it a dash that started headers, or a percent sign? And what if you can't use the Tab key because the browser uses it to switch focus to other form elements? So you may have problems with wiki-formatting and editing under the browser.

Which leads us to actually editing text under a web browser, which I contend, sucks. Part of this is the browser, which has other ideas about the Tab key, and part of this is the operating system, which has its own ideas about what keys do what (like the Mac OS's concept of the Home key, and my concept of the Home key, are at odds).

From
"P" <XXXXXXXXXXXXXXXXX>
To
"Sean Conner" <spc@XXXXXXXXXXX> (email @ work)
Subject
Re: collaboration issues
Date
Tue, 13 Mar 2007 11:57:36 -0400 (EDT)

Sean,

Here a line from shell script I'm using to keep the site lists updated automatically. Basically just a post using wget (make sure your using a up to date version of wget).

wget -O /dev/null \
	--http-user=AutoUpdate \
	--http-passwd=XXXXXXXXXXXXX \
	--post-file=$tmp/sitelist \
	http://XXXXXXXXXXXXXXXXX/twiki/bin/save/$web/$topic

You may also find the following features useful.

-P

I looked, but wasn't overly impressed (unlike my reaction to TiddlyWiki) and I'm not a fan of WYSIWYG editors (P installed one on the Twiki) but as I replied to P, I'm not all criticisms with no suggestions—I did place all my work notes (and work related files) under a webserver on my workstation, to make it easier to get to them (even if they're a bit disorganized under names that may only have meaning to me) and write a webpage to display the current IP address allocations (which uses XMLHttpRequest() to fetch the text file and generates a table view—my ultimate intent is to allow one to edit the data using the webpage and have it update the file back on my workstation).

I also started looking at various Firefox extentions to hopefully make editing under Firefox a bit more tolerable. I ended up wasting a few hours removing and reinstalling Firefox because some editing extension (sorry, I don't remember which one I found the link in a text file of all things) screwed up Firefox (by adding a large amount of blank space to the bottom of the Firefox window, which I couldn't get rid of).

And if you think I'm making a mountain out of an anthill, I'm not. This issue is currently demoralizing everyone in the company (at the very least, I'm getting demoralized) and we at The Company need to find a solution to allows us to collaborate, now that we've gone all Virtual Office.

Wednesday, March 14, 2007

“Orange you glad I didn't say ‘daemon?’”

At The Company Weekly Meeting it was decided that I should stop work on the daemon I'm writing as we have a better way of doing what we're doing (no longer are we trying to get MySQL to notify an external application of updates). I'm not upset at the loss of the work I've done so far since going in I knew this was exploratory programming and thus subject to change.

In other news, Smirk was impressed with the webpage I set up to view IP address allocations, but as all too often with quick written hacks, it too is saddled with feature requests as it lurches its way towards being a major application (in this case, Smirk asked for half a dozen changes, some easy, some not so easy).

Looks like I'll be learning even more JavaScript now.

Thursday, March 15, 2007

Hammers, screwdrivers, wrenches and paperclips

From
"Smirk" <{{charles@pickint.net}}>
To
spc@{{pick.net}} (email @ work)
Subject
ip address stuff
Date
Wed, 14 Mar 2007 16:41:49 -0400 (EDT)

Hi Sean,

I like the IP address layout you are using. Could you add some features?

The check box column should have one checkbox in the column header that would toggle all other checkboxes on or off.

-S

I spent the day working on what I thought would be something quick.

The first order of business was to get the webpage (mentioned above by Smirk) to send the information it had back to the server. And that's when I started running into some real issues (and let me just state for the record that so far I'm not a fan of JavaScript). Issues with tool use (specifically, software tools) and user expectations.

The IP files I edit look something like this:

192.168.1.0	00:00:00:00:00:00	Obnoxico & Co. network
192.168.1.1	DE:CA:FE:BA:D0:01	managed switch
192.168.1.2		|		their stuff ... 
192.168.1.3		|
192.168.1.4		|
192.168.1.5		|
192.168.1.6		|
192.168.1.7	FF:FF:FF:FF:FF:FF	Obnoxico & Co broadcast

Nice and easy to read. Vertical columns nicely arranged. But each column isn't nicely delineated in the actual “text.” Here, let me do a “reveal codes” and I'll show you:

192.168.1.0→00:00:00:00:00:00→Obnoxico & Co. network↵
192.168.1.1→DE:CA:FE:BA:D0:01→managed switch↵
192.168.1.2→→|→→their stuff ... ↵
192.168.1.3→→|↵
192.168.1.4→→|↵
192.168.1.5→→|↵
192.168.1.6→→|↵
192.168.1.7→FF:FF:FF:FF:FF:FF→Obnoxico & Co broadcast↵

The right arrows (→) represent the HT character, and the crooked arrow (↵) represents the end of line marker (under Unix, this is a single character LF whereas under Windows, this would be the two character sequence CR LF). And by using HT as a field separator, my columns don't line up logically (although visually, in my text editor, they do).

And that's an issue.

A hard issue.

Oh sure, most people can probably deal with a file that looks like:

192.168.1.0	00:00:00:00:00:00	Obnoxico & Co. network
192.168.1.1	DE:CA:FE:BA:D0:01	managed switch
192.168.1.2	|	their stuff ... 
192.168.1.3	|
192.168.1.4	|
192.168.1.5	|
192.168.1.6	|
192.168.1.7	FF:FF:FF:FF:FF:FF	Obnoxico & Co broadcast

But I can't. It would drive me up a wall. The solution would be to read in each line, expand the tabs to spaces, then pull out each field according to which character columns they're in. That would solve that problem, but it still leaves some other issues.

The last three features Smirk requested I woudn't say are necessarily hard to implement, but getting the user interface right is. Or at least, a user interface I would like (and that would be a minimum number of mouse clicks, because lord knows I don't want to have to check 32, 64 or even 128 individual check boxes to unassign a block of addresses—then again, I'd probably never use the web interface at all so that point might be moot). But what Smirk is asking for is an interface closer to how he works, which mimics a spread sheet (which I touched upon the other day).

And there's still the issue of just how much Smirk or P will update the IP list. My updating the lists hasn't been that much of an issue, and the only reason it's an issue now is the lack of updates to The Company Twiki. (what good is a knowledge base if no one bothers to update the knowledge?) And if the number of times it actually comes up that Smirk has to update the IP list is small, then perhaps writing this piece of software isn't really worth the effort (which is where I'm leaning).

On the other hand, this issue is deeper than just updating a list of IP addresses—at the core, it's a collaboration issue (even if right now it's just between Smirk, P and I) and the fact that Smirk uses hammers, I use screwdrivers and P uses a wrench. And all we have are paperclips (hmmm … that certainly came out of left field).


“undefined” vs. undefined

I had this bit of JavaScript code (never mind that I am compelled to add a semicolon to the end of each line when it isn't needed):

var lines = req.responseText.split("\n")
  
for (var i = 0 ; i < lines.length ; i++)
{
  var row = table.insertRow(-1)
  var fields = lines[i].split("\t")
  var cell;

  cell = row.insertCell(0)
  cell.textContent = fields[0]

  cell = row.insertCell(1)
  cell.textContent = fields[1]
  
  cell = row.insertCell(2)
  cell.textContent = fields[2]
}

I have a text file which I've just loaded. I break it into lines, and then each line into sub-fields, each separated by a tab (this is the format I keep my IP allocation files in), and then stuff the entire thing into a large table.

So, from a text file that looks like this (where I'm showing the actual tab and newline characters as arrows):

10.0.0.0→00:00:00:00:00:00→Backup network↵
10.0.0.1→DE:CA:FB:AD:00:01→mobybackup↵
10.0.0.2→DE:CA:FB:AD:00:02→dnsserver↵
10.0.0.3↵
10.0.0.4↵
10.0.0.5→DE:CA:FB:AD:00:03→mailserver↵
10.0.0.6↵

and I end up with something that looks like:

Sample output
IP MAC Notes
10.0.0.0 00:00:00:00:00:00 Backup network
10.0.0.1 DE:CA:FB:AD:00:01 mobybackup
10.0.0.2 DE:CA:FB:AD:00:02 dnsserver
10.0.0.3 undefined undefined
10.0.0.4 undefined undefined
10.0.0.5 DE:CA:FB:AD:00:03 mailserver
10.0.0.6 undefined undefined

The undefines pop out because there's nothing else to the line except an IP address, so fields[1] and fields[2] literally have nothing in them, not even the empty string. They are devoid of any value whatsoever.

Okay, fine, whatever.

Now, I go save what I have in the table back to the server. So I write some code:

var table = document.getElementById('tdisplay')
var textfile = ""

for (var i = 0 ; i < table.rows.length ; i++)
{
  var ip   = table.rows[i].cells[0].textContent
  var mac  = table.rows[i].cells[1].textContent
  var note = table.rows[i].cells[2].textContent
  
  textfile = textfile + ip + "\t" + mac + "\t" + note + "\n"
}

And what do I get back?

10.0.0.0→00:00:00:00:00:00→Backup network↵
10.0.0.1→DE:CA:FB:AD:00:01→mobybackup↵
10.0.0.2→DE:CA:FB:AD:00:02→dnsserver↵
10.0.0.3→undefined→undefined↵
10.0.0.4→undefined→undefined↵
10.0.0.5→DE:CA:FB:AD:00:03→mailserver↵
10.0.0.6→undefined→undefined↵

Oh wait! That's not what I wanted! Okay …

for (var i = 0 ; i < table.rows.length ; i++)
{
  var ip   = table.rows[i].cells[0].textContent
  var mac  = table.rows[i].cells[1].textContent
  var note = table.rows[i].cells[2].textContent

  if (!ip)   { ip   = "" }
  if (!mac)  { mac  = "" }
  if (!note) { note = "" }
  
  textfile = textfile + ip + "\t" + mac + "\t" + note + "\n"
}

And now let's see what I get:

10.0.0.0→00:00:00:00:00:00→Backup network↵
10.0.0.1→DE:CA:FB:AD:00:01→mobybackup↵
10.0.0.2→DE:CA:FB:AD:00:02→dnsserver↵
10.0.0.3→undefined→undefined↵
10.0.0.4→undefined→undefined↵
10.0.0.5→DE:CA:FB:AD:00:03→mailserver↵
10.0.0.6→undefined→undefined↵

Whoah! Wait! It looks like that doesn't work. Do some reading, oh, I need to use the “===” equality operator instead of the “==” equality operator (shades of Lisp here).

for (var i = 0 ; i < table.rows.length ; i++)
{
  var ip   = table.rows[i].cells[0].textContent
  var mac  = table.rows[i].cells[1].textContent
  var note = table.rows[i].cells[2].textContent

  if (ip   === undefined) { ip   = "" }
  if (mac  === undefined) { mac  = "" }
  if (note === undefined) { note = "" }
  
  textfile = textfile + ip + "\t" + mac + "\t" + note + "\n"
}

And I get …

10.0.0.0→00:00:00:00:00:00→Backup network↵
10.0.0.1→DE:CA:FE:BA:D0:01→mobybackup↵
10.0.0.2→DE:CA:FE:BA:D0:02→dnsserver↵
10.0.0.3→undefined→undefined↵
10.0.0.4→undefined→undefined↵
10.0.0.5→DE:CA:FE:BA:D0:03→mailserver↵
10.0.0.6→undefined→undefined↵

That's not working? What's going on here?

Then a lightbulb goes on. The variable note isn't undefined, it's "undefined", as in, the string consisting of the letters u-n-d-e-f-i-n-e-d. I changed the code used to construct the table:

var lines = req.responseText.split("\n")
  
for (var i = 0 ; i < lines.length ; i++)
{
  var row = table.insertRow(-1)
  var fields = lines[i].split("\t")
  var cell;

  cell = row.insertCell(0)
  cell.textContent = (fields[0] !== undefined) ? fields[0] : ""

  cell = row.insertCell(1)
  cell.textContent = (fields[1] !== undefined) ? fields[1] : ""
  
  cell = row.insertCell(2)
  cell.textContent = (fields[2] !== undefined) ? fields[2] : ""
}

And I finally got what I was expecting:

10.0.0.0→00:00:00:00:00:00→Backup network↵
10.0.0.1→DE:CA:FE:BA:D0:01→mobybackup↵
10.0.0.2→DE:CA:FE:BA:D0:02→dnsserver↵
10.0.0.3→→↵
10.0.0.4→→↵
10.0.0.5→DE:CA:FE:BA:D0:03→mailserver↵
10.0.0.6→→↵

Now, I had originally written this as an indictment against dynamically typed languages, but really, it's not, now that I think about it. C can also have undefined variables, but they're usually pointers, and they usually contain NULL (less rarely, some other illegal address). I think my problem here was a mental mismatch with what was actually going on, which I'm finding is all too easy in a dynamically typed language like JavaScript. Was the variable undefined because it was actually undefined, or was it "undefined"?

Would using a statically typed language helped me here? Possibly. It might have forced the issue of “undefined” at compile time. Or possibly not (on my system, doing something like printf("%s\n",NULL) results in “(null)” being printed, which isn't catching the problem at compile time). But the hiding the issue (or in this case, not crashing) makes it harder to debug such things.

Friday, March 16, 2007

“Go away! We don't want you!”

I'm having to do some work on SugarCRM, and I just now noticed that the default installation has a robots.txt file:

User-agent: *
Disallow: /

As written, this will prevent the site from being indexed by the various search engines. I wonder how many people using SugarCRM are aware of this? Or even care? I couldn't find anything about it mentioned in the documentation, but I just did a cursory search.

Saturday, March 17, 2007

A memo to myself

Rethink ordering take-out from that Chinese restaurant.


The Emperor's New Security Detail

You're about to read a real-life heist story. Super Bowl XLI was a Level One national security event, usually reserved for Presidential inaugurations. We had to get two full vanloads of materials through federal marshals, Homeland Security agents, police, police dogs, bomb squads, ATF personnel, robots, and a five-ton state-of-the-art X-ray crane. It took four months and a dozen people to pull off the prank that ended up fooling the world.

This is the Super Stunt.

Via Jason Kottke, Super stunt: The most ambitious prank in history.

On the one hand, I think this is great that four guys were able to pull this off and to show just how silly excessive security really is. On the other hand, this is downright scary that four guys were able to pull this off at a Level One National Security Event. On the gripping hand, I hope the guys don't end up at Guantanamo Bay for pointing out the Emperor's President's new security detail.

Sunday, March 18, 2007

No longer home alone

Spring and Wlofie returned from Gulf Wars late tonight, tired, a bit grungy, and with a boat! How they ended up with a fairly modern small fishing boat at a Medieval re-enactment festival is just one of those questions I've learned not to ask.

I will say, however, that the cats are happy to have more worshippers humans about Casa New Jersey. Now, maybe they'll leave me alone.

Monday, March 19, 2007

Short day

It's a short day today, as I have to go to bed early in order to make it to the West Palm Beach County Courthouse for jury duty by 8:00 am.

Is the sun even up at that hour?

Ick.

Tuesday, March 20, 2007

Notes from a courthouse

I left Casa New Jersey about twenty minutes later than I wanted to, but I still made it to the West Palm Beach County Courthouse on time (well, a few minutes past 8:00 am, but I think they said 8:00 am to ensure everybody shows up by the real time of 9:00 am). Traffic was a bit hectic, and the instructions given had jurors parking about two miles south of the actual courthouse at the convention center.

From the convention center it was a short bus ride to the courthouse where all jurors (over 200) checked in and sat around waiting. After an introductory instructional film (which pegged a few hot buttons of mine, but more on that when I have time) I was immediately called as a potential juror, unlike the last time where I got called at the end of the day.

But like last time, I did get called to be an actual juror. After voir dire we got a lunch break and there is wi-fi at the court house—oops, gotta get back to court.


A message to someone

[Hippo]
[Birdy]
[Two ewes]

More on this later

I heard one half of the case today. At 5:30 the judge asked if we jurors wanted to go home, or continue (only he took about ten minutes to explain that). It was fairly unanimous that we continue tomorrow.

I got home in time to head on out to dinner for a special occasion. I just now got home.

I'm tired.

I'm going to bed.


An unholy alliance if there ever was one

I'm going to bed but first, a link (via Flutterby) to a case going before the Surpreme Court that has both the ACLU and the American Center for Law and Justice (aka Pat Robertson) on the same side.

And what can unite these two forces behind the defendant?

Bong Hits 4 Jesus (and in the immortal words of Dave Barry, “I am not making this up”).

Wednesday, March 21, 2007

untitled

“Mr. Conner, is there any reason I shouldn't have you arrested?”

“No. No reason at all.”

Yes, that was my answer to a very furious judge. I can only suppose that such an answer to such a question was a very brave (or a very foolhardy) thing to do; the judge did not have me arrested for such a candid answer (much to my and the bailiff's relief).

So, how did I, on day two of jury duty, find myself standing in front of an irate judge ready to arrest me?

You see, it all started when I failed to set my alarm clock correctly. We were instructed by the judge to return today at 9:00 am. I thought I set my alarm clock for 7:00 am, but I missed one small little detail: 7:00 pm.

Sigh.

I woke up and noticed it being brighter than I expected. I took a look at the clock—9:23 am.

XXXX!

Ten minutes later I was showered, dressed and putting on my shoes when I received a call from the West Palm Beach Courthouse asking where I was. I apologized profusely and said I was walking out the door.

The drive was stressful, hitting every light, stuck behind every slowpoke. I was almost to the I-95 on-ramp when I realized I forgot my jury badge.

XXXX!

It was one of those “damned if I do, damned if I don't” type decisions—do I need that badge? Will not having it be more trouble than being even later? I erred towards having it. That cost me quite a bit of time.

The traffic lights slowed me down.

So did the traffic.

And the rail road crossing with the non-existent train crossing.

It seems my karma got mauled by dogma. Or something like that.

By the time I arrived at the court room, it was 10:31 am.

Now, when the courthouse called, I was instructed to report directly to the courtroom. But when I got there an hour and a half late at 10:31 am there was no one outside. I cautiously entered to find the trial well under way.

As the bailiff led me to the benches in front of the court, the judge called a five minute recess, and then had the bailiff escort the jury to the jury room. After they left, he asked if all the jurors had been escorted out of the room. Um, I thought, aren't I a juror? I raised my hand and made some form of noise—

“Quiet,” said the judge. “I don't want to hear from you.” He leaned back. “No, not you,” he said, talking to the defendant. The courtroom was quiet for a minute. “Bailiff, please escort Mr. Conner to the podium.” Pause while I was escorted. Once there, the judge rattled off contempt of court charges, which included a month of jail time and fines, and would I like to explain what exactly happened?

After I spoke, well … that brings us up to the start of this entry.

The actual punishment dealt out to me by the judge was about as bad as internal detention one would get in high school. I had to go back to the Jury Assembly Room and sit there for the rest of day to reflect on my actions of this day.

And boy, did I reflect. I felt awful, having wasted not only the judge's time, but that of the defendant and other jurors (the lawyers, not so much since they're probably earning a few hundred bucks per hour). By the time I got to the Jury Assembly Room I was in tears.

Horrible experience. Although I did call my friend Hoade (using the Stupid Cell Phone Trick of dialing 800-FREE-411 to get his number. Talking to Hoade will always cheer me up.

But that's it. I technically served my time as a juror, and, given what happened today, I would be surprised to find myself called anytime soon.

Thursday, March 22, 2007

untitled II

Now, about that court case

Yesterday I ran into one of the jurors during lunch (oh, the judge wasn't that sadistic as to feed me only bread and water). Since the jury was removed from the courtroom before my dressing down, he was curious as to what exactly happened. So I told him what happened, and he told me that later on, the judge also dressed down one of the witnesses on the stand.

I can only surmise that the judge was having a bad hair day.

I also gave him my email and phone number so that I could get some closure to the case once it's over. This morning he called and gave that closure.

Now, since the case is over, I can talk about it. The defendant was charged with DUI, with a BAL of 0.12 (which does exceed the Florida legal limit of 0.08). During the trial, it came out that he was involved in a motocycle accident (he was driving the motocycle) and that his passenger, his wife, died in the accident. His blood was drawn as evidence two and a half hours after the accident, and by using a formula (I forgot the actual name, but it was something like “retrograde determinant” or something like that) his BAL at the time of the accident was between 0.14 and 0.17, twice the legal limit.

The testimony I heard was the State's side, and I missed the defendant's side of the story, but the State's evidence was strong and there was no way the alcohol in the defendant's blood could have risen after the accident.

He was found guilty.

Now, the full story (the juror researched the background after the trial—some of the following details did not make it to the courtroom). The accident happened on September 25th, 2005, on the defendant's birthday. He, and a bunch of friends had been bar hopping all day and were on their way to another bar when an alien (and I don't remember if the alien was illegal or not) hit the defendant, causing the accident (so it wasn't the defendant that caused the accident). The alien had been stopped four times previously for driving without a license. The defendant's wife died at the scene, but the defendant wasn't told this for three days (apparently he had extensive injuries, and in the courtroom he walked with a cane and a pronounced limp).

The juror I spoke with was upset at having to deliver a guilty verdict, but as per instruction by the judge, he was guilty of driving under the influence. And I really feel for the defendant.

He was only sentenced to twenty days in jail, though.

Friday, March 23, 2007

Hot buttons

The other day I mentioned the jury instructional film setting off a few hot buttons of mine, but I forgot about it until Bunny reminded me about it.

The first hot button—democracy. We are not a democracy. A democracy is two wolves and a lamb voting on what's for dinner. No, we are a representational republic with democratic leanings. That's where the two wolves and the lamb appoint representatives and the choice of dinner ends in deadlock, as it should be. But this is a minor gripe compared to the next one.

The other hot button that got pressed—“jury of your peers.” Yup, the film actually said “we have a right to a trial with a jury of your peers.”

No!

No, no, no, no, no, no, no, no, and no!

Article 3, § 2 of The Constitution of the United States (emphasis added):

The trial of all crimes, except in cases of impeachment, shall be by jury; and such trial shall be held in the state where the said crimes shall have been committed; but when not committed within any state, the trial shall be at such place or places as the Congress may by law have directed.

Amendment VI of the Constitution (emphasis added):

In all criminal prosecutions, the accused shall enjoy the right to a speedy and public trial, by an impartial jury of the state and district wherein the crime shall have been committed, which district shall have been previously ascertained by law, and to be informed of the nature and cause of the accusation; to be confronted with the witnesses against him; to have compulsory process for obtaining witnesses in his favor, and to have the assistance of counsel for his defense.

and Amendment VII of the Constitution (emphasis added):

In suits at common law, where the value in controversy shall exceed twenty dollars, the right of trial by jury shall be preserved, and no fact tried by a jury, shall be otherwise reexamined in any court of the United States, than according to the rules of the common law.

Do you see “peers” stated anywhere in the Constitution?

No.

Why do you not see “peers” stated in the Constitution?

Because we don't have a peerage system here in the United States, despite our legal system having largely derived from England.

Why do we not have a peerage system in the United States?

Because our Founding Fathers specifically rejected the peerage system.

I knew our educational system was bad, but this bad?

Sheesh!

Saturday, March 24, 2007

Da-da-da-duuuuummmmmmm!

As long as I'm not a party, I find arguments amusing. Once, when working at IBM I nearly laughed out loud during an argument that took place in a meeting (and got dressed down by my team leader—there's a reason why I don't have a real job).

I also find arguments fun to write—there's just something inherently silly about an argument when two people are arguing past each other. But I never thought to set an argument to Beethoven's Fifth Symphony (link via news from me), much less improvise it live on TV.

Sunday, March 25, 2007

A self-referential post demonstrating the lameness of meta blog humor

I hate blog posts that are nothing more than a note saying there's nothing to blog about.

Don't you?

Monday, March 26, 2007

Notes on what geeks find interesting

I've been using Linux for over twelve years now, and I'm still learning it.

Today, Wlofie and I spent a few hours doing Stupid Shell Tricks under Linux—stuff like naming files “ ‥ ” (that's space period period space or even “ . * & ! prang” (that's space period space asterisk space ampersand space explanation point space "prang") or even “-rf *”—names that give the Unix shell fits (or naive users fits trying to get rid of such files).

From there, we ventured into the territory that crackers use to hide their activities under Unix systems. One such trick is the following command:

GenericUnixPrompt> hacker_tool || rm -rf ./

Kill the running hacker_tool process and all the files are removed. A process listing will only show the hacker_tool running. A smart cracker will zap or munge the history file of the shell. So that's a pretty hard thing to detect.

Another trick a cracker will do to make things difficult is:

GenericUnixPrompt> hacker_tool &
[1] 4532
GenericUnixPrompt> /bin/rm hacker_tool

This starts the hacker_tool, then the executable is removed. The program still runs since the code is in memory, but there's no way to actually recover the executable.

Or so I thought.

Wlofie showed me this though (at least, under Linux):

GenericUnixRootPrompt# cd /proc/4532
GenericUnixRootPrompt# cp exe /tmp/recovered_executable_file
	# or alternatively
GenericUnixRootPrompt# dd if=exe of=/tmp/recovered_execuable_file

Ah, the things geeks find interesting.

Tuesday, March 27, 2007

“The tires will only last for about 15 minutes, but it's okay because the fuel runs out in 12 minutes.”

I've written about the Bugatti Veyron, the obscene 1,000Hp 8 liter W-16 production car that tops out at over 250mph (but at a price—a million for a car that gets only three miles per gallon).

But man, it certainly looks very fun to drive (via Jason Kottke).

Wednesday, March 28, 2007

“But, it goes to 11.”

Smirk has a theory that every ten days or so, things go crazy and it's difficult to cope with what's being thrown at you.

Today is a day ten (short version—no Internet at Casa New Jersey, which means no email (and the troubles in getting an alternative email server set up), and many pointless trips to a customer site trying to get a new router configured).

But, despite how bad my day was, it wasn't as bad as Spring's, who had to endure a company work reschedule, a late train, and is now stuck in Atlanta due to a cancelled flight (she's on her way to visit The Kids in Colorado), and that's just the not so bad things that happened.


Virtually working

So, like, if Casa New Jersey has no Internet, how can I post?

I'm staying at Bunny's house. And for the next few days I'll be working from Bunny's house. Given that The Office has gone all virtual (oh yes, a few months ago actually—it's great working mostly from home and it saves a ton of money on gas), what with VoIP phones and what not, I can really work from anywhere that has an Internet connection.

And I finally got my email situation worked out.

Thursday, March 29, 2007

“Scotty, Mi devas deform rapido en tri minutoj aŭ ni ĉiuj estas mortinta!”

William Shatner is William Shatner, even in Esperanto.


“Remember, we're all in this together.”

Brazil, 1985, directed by Terry Gilliam, written by Terry Gilliam, Charles McKeown, and Tom Stoppard. In Brazil, Terry Gilliam asks the audience to imagine a world where the government wages a never-ending war with shadowy terrorists, a world where civil liberties are being destroyed in the name of security, a world where torture becomes official state policy in order to conduct more efficient interrogations of suspected terrorists. What's more, in Gilliam's fictional world, the central government is not just secretive but incompetent. Mistakes are made, leading to the imprisonment and torture of innocents. Most offensive of all, Gilliam implies that such a government could exist without its citizens staging an armed revolt. I'm usually willing to suspend disbelief, but this goes too entirely too far.

Via Jason Kottke, #51: Brazil

Yeah, he's right—a government like that could never happen.


I'm ambivilent about network neutrality

I've been wanting to write this for a few months now (and the orginal intent was to write it for the other site but I'm not sure if Smirk would agree with me) but since Jason Kottke linked to Craig “Craigslist.org” Newmark's article on the subject, I figured it was time.

Net neutrality.

Should the network be neutral in the traffic it transports, or can it prioritize the data depending upon content, destination, or both? It's an argument with proponents on both sides of the issue and it pretty much breaks down into individuals and small companies wanting neutrality, while the large multinational corporations want to shape the traffic.

Me?

I personally would like to see a neutral Internet, but I also see no problem with companies doing what they want to network traffic they carry. What I don't want to see is government regulation of what can and can't be done on the Internet. And generally, I feel the whole movement is moot anyway, because the net will always be neutral.

How?

Economic, my dear Watson.

Data is transfered across the Internet using the Internet Protocol, IP. To transfer a file, it's broken up into small bundles of data called packets, wrapped with a source address (where it's coming from) and a destination address (where it's going to), and pumped out through some piece of hardware (an Ethernet card, USB, serial line, T-1, OC-3, heck, IP packets can even be transported using avian carriers) to another device that's closer to the destination. That device then takes the packet, looks at the destination address, and pumps the packet out some hardware port to another device that's closer, and the process repeats until the destination is reached, on average, in less than 20 such hops.

Now, the closer to the “core” you get, the more packets a router (a dedicated device to sling packets around) has to handle. To this end, most routers have hardware dedicated to slinging the packets around, and since the destination address is at a fixed point on the IP packet, it's easy (relatively speaking) to make dedicated hardware for this function. And it's important this be fast, because a core router may be handing 50,000 packets a second (the router The Company's traffic flows through handles about 4,000 packets a second) and comparing each destination address against a routing table with perhaps 200,000 possible destinations. Assuming a binary search on the routing table, that's 17 comparisons on average per packet (18 max), times 50,000 packets per second, or 850,000 comparisons per second, or about one comparison per µsecond.

But the second other criteria are added to the routing entries, fewer packets can be processed on a given router. Say you want certain source addresses to be routed over faster links. Now, not only do you have to scan the destination address, but the source address as well. But the dedicated hardware in routers are only there for scanning destination addresses—scanning other parts of the packet require the CPU in the router to handle the packet.

Ouch.

And scanning deeper into the IP packet, say, for a TCP port (like TCP port 80, which is the default port HTTP runs over) requires some additional processing to locate the TCP header, since the IP header is variable in length.

Ouch.

And then there's the administrative overhead.

Oh yes, maintaining a list of “fast addresses” (say, to partnering networks) isn't free. There's overhead in maintaining the list. There's overhead in distributing the list to all the routers across a network. There's overhead in troubleshooting: “Why did the packets go there?”—a few hours later—“So, which is more important, streaming video from Viacom to AT&T or VoIP from AT&T to Verizon?”—a few days later—“But if we do that, that impacts the data from Sprint, who just signed a major deal with us.”

Ouch.

And my example there assumes that AT&T hasn't already bought Verizon. Heck, in these days of multinational mergers it's hard to know who owns what; just the politics of running a non-neutral network is mind-boggling to me, never mind the technical aspects of it.

A simple network is cheaper to run. A simple network is faster too.

Cheaper to run. Faster. Higher profit margin. I would think this would be a no brainer.

Oh, and did I mention that the current version of IP, which was designed over thirty years ago, has a field for “Quality of Service” which is rarely, if ever, actually used? Why? A few reasons:

  1. The most commonly used network API, the one from BSD Unix, never had a way for applications to set this field.
  2. It slows down a router (see above).
  3. It's an administrative nightmare. Heck, BGP, a routing protocol between networks, is an administrative nightmare and that's just dealing with destination addresses—it doesn't deal with quality of services at all.
  4. There's no guarentee that the network you send traffic to even supports “Quality of Service.”

It's been found over and over again that it's cheaper and easier to make faster routers than to implement quality of service across the network.

So I'm of the opinion—let the big boys waste their money on smart networks. Let them learn the hard way that a stupid network is, in the long term, better.

And that's why I'm not really concerned about network neutrality. The market will sort it out.

  1. I tried finding an actual number for the average number of hops across the Internet but the only numbers I could find (about 15) were for 1999–2000 with nothing more recent. Given the growth since then, I'll play it safe and say the average is no more than 20. [back]
  2. And it wouldn't surprise me if I'm underestimating the number of packets per second by an order of magnitude. [back]

Update on Friday, March 30th, 2007

Added a link to Wikipedia, and a small addendum to this entry.

Friday, March 30, 2007

Still ambivilent about network neutrality

I read up on net neutrality on the Wikipedia and while I learned quite a bit that I didn't know (like “quality of service” is more prevalent that I expected) it still didn't change my feelings towards the issue, but it's still worth reading.

Saturday, March 31, 2007

Incommunicado

Well, we still don't have Internet access at Casa New Jersey, so new entries may be spotty over the next few days until connectivity is restored.

You have been warned.

Obligatory Picture

[Don't hate me for my sock monkey headphones.]

Obligatory Links

Obligatory Miscellaneous

You have my permission to link freely to any entry here. Go ahead, I won't bite. I promise.

The dates are the permanent links to that day's entries (or entry, if there is only one entry). The titles are the permanent links to that entry only. The format for the links are simple: Start with the base link for this site: http://boston.conman.org/, then add the date you are interested in, say 2000/08/01, so that would make the final URL:

http://boston.conman.org/2000/08/01

You can also specify the entire month by leaving off the day portion. You can even select an arbitrary portion of time.

You may also note subtle shading of the links and that's intentional: the “closer” the link is (relative to the page) the “brighter” it appears. It's an experiment in using color shading to denote the distance a link is from here. If you don't notice it, don't worry; it's not all that important.

It is assumed that every brand name, slogan, corporate name, symbol, design element, et cetera mentioned in these pages is a protected and/or trademarked entity, the sole property of its owner(s), and acknowledgement of this status is implied.

Copyright © 1999-2017 by Sean Conner. All Rights Reserved.