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, Tes t Tube Aliens: Gadget of the Week
You know … this just … fifteen dollars … words … fail me.
Next thing you'll know, peopl e 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 attacks—naps.
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:
- Bloglines/3.1 (http://www.bloglines.com; 14 subscribers)
- Feedfetcher-Google; (+http://www.google.com/feedfetcher.html; 8 subscribers; feed-id=7978511864245132053)
- LiveJournal.com (webmaster@livejournal.com; for http://www.livejournal.com/users/bostondiaries/; 16 readers)
- InsaneJournal (webmaster@insanejournal.com; for http://www.insanejournal.com/users/bostondiaries/; 4 readers)
- Feedshow/2.0 (http://www.feedshow.com; 1 subscriber)
- YahooFeedSeeker Testing/2.0 (compatible; Mozilla 4.0; MSIE 5.5; http://publisher.yahoo.com/rssguide; users 3; views 125)
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.
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:
- 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 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 wellgdb
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.
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, E ric'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%.”
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 “—” (which makes a nice “—”) or even “``” (two backtics, which on most keyboards is in the upper left corner) gets translated to “ 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
- 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
- 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 ofwget
).wget -O /dev/null \ --http-user=AutoUpdate \ --http-passwd=XXXXXXXXXXXXX \ --post-file=$tmp/sitelist \ http://XXXXXXXXXXXXXXXXX/twiki/bin/save/$web/$topicYou may also find the following features useful.
- http://twiki.org/cgi- bin/view/Plugins/PluginPackage
- http://twiki.org/cgi- bin/view/Plugins/AddOnPackage (take look the MailToTwikiAddOn)
- http://twiki.org/cgi- bin/view/Plugins/ContribPackage
-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?
- add a location feild (boca, charlotte, other building, etc)
- add a contact name & number field
- add a subnet field
add a checkbox for each record that would allow one to tuplicate info from one box to many, or to clear all data for unassigning:
i.e. duplicate all info from row x.x.x.x to selected boxes
unassign all checked boxes
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:
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
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 [1].
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 [2].
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:
- The most commonly used network API, the one from BSD Unix, never had a way for applications to set this field.
- It slows down a router (see above).
- 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.
- 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.
- 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]
- 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.