November 14, 2002

Something’s wrong

Finished up prototype firewall for client, brought it into the office tonight. To timeout on the serial/VGA console selection I was talking about yesterday in grub (“Press any key to continue” on both consoles indefinitely) add the --timeout=<nsecs> option to the terminal command. Hopefully I can get cracking on the 12 systems for this project over the weekend. I’ll have some FreeS/WAN configuration to do, and the usual stuff like IPs. iptables configuration to do on them as well.

Did some coding today too. Finished up the SQLWikiPage and the SQLWikiPageContainer. Wait, was that today or yesterday? I was working on the recursive page interpreter today, and hit a bunch of snags with that. I don’t think it’s going to be actually recursive. Instead the plug-ins that are being called to inspect text can “enter” or “leave” a “frame”. Someday I’ll make that more clear.

Played TSO a bunch last night. Trying to figure out whether you make money faster with maze or code. We did code last night with skills 3/0/8 IIRC, and got about $66 per solution. On maze we were probably averaging somewhere around $300-$325 I’d say. I’ve got like $12,000 now. I had something like $6,800 at the beginning of the night I think. darkho and I have maze down pat.

I’ve been walking around humming/singing/thinking the songs I downloaded from “Donnie Darko”, especially “Head Over Heels” by Tears for Fears. I’ve been exceptionally tired. I feel like I’m developing carpal tunnel syndrome — or something equally painful sounding — in my right wrist; it started from playing TFC at practice on Sunday night. What the fuck is wrong with me?

The tiredness is really getting to me. My code quality went to shit tonight. I’m even feeling my eyelids getting heavy writing here, which doesn’t usually happen. Maybe I’m just not sleeping well? Maybe I really do need a bigger bed? I can test this theory tomorrow perhaps. Maybe I’ll turn off my phone and sleep until 1300 or so.

As usual, there’s something missing in my life. Passion? Excitement? Drive? Red meat? Social interaction? I couldn’t tell you. It’s just a feeling I get from time to time, kind of a longing. Watching “Donnie Darko” this past weekend started this bout of it; sometimes it’s better sometimes it’s worse. I bet it’s always there, though.

Sometimes I feel like things are happening too quickly and I’m not paying enough attention. Sometimes it feels like I’m never right, which is a big deal for me: I quite like to be right. It’s like everything I come up with is a hastily-conceived hypothesis, anemic and bound to be rejected eventually. Sure, when it comes to things like simple math or computers I can be reasonably certain. Whenever I think about human nature, or motivation, or relationships, the nagging feeling that I’m wrong is always just there under the surface. It’s a voice in the back of my head that says “YOU MUST KILL THEM”– wait, no, wrong voice. It is a voice in my head, though, of sorts, and it’s always asking “what if?” I have trouble accepting that.

I think I came to the conclusion today that I have trouble articulating my feelings. Can you tell?

I’m going to go to bed now. Maybe I’ll dream of something dramatic. Or maybe it’ll just be some weird scene with me and a random chick from middle school naked in a gym shower where we mutually consider playing checkers.

November 12, 2002

Fighting with serial

Early entry so I can get this bit about serial console out of the way.

So I was fighting with RH8 serial console today. Here’s my /etc/grub.conf:

serial --unit=0 --speed=9600
terminal console serial
default=0
timeout=10
splashimage=(hd0,0)/grub/splash.xpm.gz
password --md5 ...
title Red Hat Linux (2.4.18-17.8.0)
	root (hd0,0)
	kernel /vmlinuz-2.4.18-17.8.0 ro root=/dev/md2 hdc=2434,255,63
console=tty0 console=ttyS0,9600
	initrd /initrd-2.4.18-17.8.0.img

(Note that I wrapped the kernel line for readability.) Then at the end of /etc/inittab I’ve got:

S0:12345:respawn:/sbin/agetty 9600 /dev/console vt100

Now initially, per the mingetty(8) man page, I used mgetty. I was using mgetty like so:

S0:12345:respawn:/sbin/mgetty -s 9600 -r -x 9 ttyS0

Hint to Red Hat 8.0 (Psyche) users: don’t use mgetty for serial console. Use agetty instead. agetty comes in the util-linux package which you already have; mgetty you might not, as it comes in its own package. To describe the symptoms that led me to this condition: mgetty would give me the login prompt, but when it went to execute /bin/login, I would cease to get any output on the serial terminal. I could strace login, or mgetty after login died, and I’d see the keystrokes coming through, but they weren’t getting to my serial terminal apparently. Also, an strace of login would show:

ioctl(0, SNDCTL_TMR_CONTINUE, {B9600 opost isig icanon echo ...})
= -1 EINTR (Interrupted system call)

SNDCTL_TMR_CONTINUE is actually TCSETSF, BTW, per ioctl_list(2). mgetty’s info page describes seemingly the same problem and provides a solution or two. Here’s excerpts:

mgetty works, /bin/login hangs

TSO, fan mail, coding

Surprisingly, the first (real) messages I got from my web log are from people wanting me to help them… with The Sims Online (TSO). One person wanted my key (see comments section). Of course, if I had given this person my key, my ability to play would be sporadic (as would the other person’s) if my account wasn’t canceled for having too many duplicate sign-on attempts — or because the person gave my key to some of his friends on alt.2600.cracks or something.

I did play a bunch of TSO yesterday. I like the maze game. I got interested in the code game, as well, even though I have yet to play it. I thought it was an interesting problem to solve.

Premise: you’re given three slots that can each contain one of the three letters A, B, or C. The code machine picks a code, and you have to guess it. Each time you make a guess, it tells you how many of the letters you picked were the correct letter in the correct place.

My solution was the same as most people’s solution: try AAA then BBB. This tells you how many A’s, B’s, and C’s are present in the puzzle. I then proceeded to try every combination of those letters. For example, if AAA = 1 and BBB = 2, that means there is 1 A and 2 B’s. I’d try ABB, BAB, and BBA. My only optimization was in the case where AAA = 1 and BBB = 1, meaning there is 1 of each letter in the puzzle. In this case, I’d call “BBC” and “ACA” and use the following table to determine the answer:

BBC matches

ACA matches

Solution

0

0 CAB

0

2 ACB

1

1 CBA

1

2 BCA

2

0 BAC

2

1 ABC
Note that this method was more or less conceived experimentally. I basically happened upon BBC and ACA for use above, and I’m sure there are other combinations that would work. With the addition of the above table, this method ensures that any code can be guessed within 5 guesses. Its average lies around 4 guesses (this determined experimentally; see below).

Then someone went and beat me. I suspect they used more math and logic, whereas randomness and experimentation were my friends. They came up with this “flow chart” reproduced as best I can here:

=> AAA
       0 => BBB
                0 => CCC
                1 => ABC
                         0 => CCB
                         1 => BCC
                         2 => CBC
                2 => ABC
                         0 => BCB
                         1 => CBB
                         2 => BBC
       1 => ABB
                0 => BAC
                         0 => CCA
                         1 => BCA
                         2 => CAC
                1 => BAB
                         0 => ACC, CBA
                         1 => BBA
                         2 => CAB
                2 => ABC, ACB
       2 => ABB
                0 => BAA, CAA
                1 => AAC, ACA
                2 => AAB, ABA

How to read this: start with AAA. Then based on the number of matches you’d go down to the line that starts with that number and follow the next guess. Repeat this until puzzle is solved. Lines with two solutions separated by columns mean you have to try both solutions. For example, lets say I’m working with the puzzle CBA. I’d first guess AAA and get 1 matches. I’d go to the 1 under AAA and see “=> ABB”. So I’d guess ABB and get 1 matches. Then I’d go to the 1 under ABB and see “=> BAB”. So I’d guess BAB and get 0 matches. Then I see “=> ACC, CBA”. So first I’d guess ACC which wouldn’t solve it, then I’d guess CBA which is the solution. Note that this example shows the longest case, which is five guesses. Using the same methods as above, I’ve found this method to be closer to 3.5 or 3.6 average turns. Someone made a nice graphic flow chart for this, but I’m too lazy to pull out the URL. If you have TSO, just check the forums, in the “Game Hints” topic or something I believe.

In the process of experimenting with all this, I created tso.py. This allowed me to code up solutions and check them easily, debug them, run them against each other, and make a simple interactive mode. Here’s an example session with tso.py:

[darkness@darktop-2 tso]$ python2
Python 2.2 (#1, Apr 12 2002, 15:29:57) 
[GCC 2.96 20000731 (Red Hat Linux 7.2 2.96-109)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from tso import *
>>> runSolvers (simpleSolver2, tableSolver, randomSolver2)
Ran 1000 tests
Solver # 0:  4.024000 average tries, 5 maximum tries, 100.00% solved
Solver # 1:  3.506000 average tries, 5 maximum tries, 100.00% solved
Solver # 2:  6.231000 average tries, 13 maximum tries, 100.00% solved
>>> debugSolver (simpleSolver2, puzzleInstance = Puzzle ("cba"))
Solving puzzle 'cba'
DEBUG: numA=1 numB=1 numC=1
DEBUG: [simple] Got abc
DEBUG: [simple] matchACA=1 matchBBC=1
Puzzle solved in 5 tries
>>> debugSolver (tableSolver, puzzleClass = InteractivePuzzle)
Solving puzzle ''
Match request: aaa
Number of matches? 1
Match request: abb
Number of matches? 1
Match request: bab
Number of matches? 0
Match request: acc
Number of matches? 0
Match request: cba
Number of matches? 3
Puzzle solved in 5 tries

You’ll note the output of runSolvers in the above output. simpleSolver2 is the first algorithm I described above, and tableSolver is the second algorithm. randomSolver2 randomly tries combinations in a semi-intelligent manner by eliminating solutions that aren’t possible based on past guesses. (See randomSolver for a straight and simple random guesser.) Note that tso.py does require a 2.x Python IIRC, and quite possibly requires at least 2.2.

By now, it should be clear that I’m insane. I spent a long time, working on a simple puzzle, without applying some sensible practices (like LOGIC and MATH), working on the optimal solution for a game within a game that I haven’t even played yet. Yeah.

In other news, I successfully rebooted a client’s machine remotely three times in a row including a kernel update. Shocking, I know. They have a Seagate ATAPI (IDE? What?) tape drive. I originally thought it was running with IDE SCSI emulation, and thought it was dying because I couldn’t do mt -f /dev/nst0 fss 1. As it turns out I was either playing with a non-existent drive or sending mt commands to the CD-ROM drive. The tape drive is fine and probably just doesn’t support fss. This all started when the client’s backup wasn’t running at night. They switched out a tape today and I rebooted it, so between the two I guess (hope) it fixed the problem. Now if I can just avoid being woken up tomorrow with any problems that occurred as a result of the reboot.

Did some coding tonight. Finished DarkWiki::SQLWikiPageContainer sort of, and most of DarkWiki::SQLWikiPage. Will probably work on other things for the next couple days.

I’ve been listening to songs from “Donnie Darko” repeatedly today and yesterday. Actually, I caught the movie again Saturday night and totally loved it again. Totally loved it. Awesome movie. You must see this. The next day I ordered the soundtrack (from http://www.cdbaby.com/) and the DVD (not from Amazon, Buy.com, or Best Buy… though I have trouble remembering who the enlightened Internet community is boycotting this week). I’ve collected the songs from the movie that apparently aren’t on the soundtrack (it’s actually the original score, IIRC) and hope to graft them onto a CD-R. Watch the damn CD be copy protected. You can bet I’ll be motivated to do some DMCA violations then.

Seriously. See this movie.

Oh, I almost forgot since I missed a few entries. ardent has asked me to be best man (or Best Man?) in his wedding and I have accepted. Very kind of him, really. I think. I have a bunch of stuff to do now, I believe, like making a Bachelor party and some speeches and shit. I should probably Google for the duties of a best man, since I have no clue. Highest I ever got within my family was “Junior Usher.” As I talk to people about this position in the wedding party, no one has heard of it, which makes me believe they fabricated this position so I didn’t have to be Ring Bear (or Ring Bearer? or ring bear[er]? Yeesh) again. I was too old and way too sexy for running down the aisle with that pillow or whatever, anyway. Too sexy for your church, so sexy it hurrrrrts.

Right Said Fred have forever made their mark upon history, I think.

November 9, 2002

La la la

Did some good coding today. Wrapped up Log4perl into a nice class for use in my system. Finished the component manager class too. I avoided premature optimization in the process: the easiest and most apparently simple way to wrap a class in a particular proxy was to make a proxy instance for every concrete instance, and set up the proxy instance. It might be too slow, but I’ll get to that later.

I found a problem with my interface.pm as well: when a class uses Exporter like use base qw(Exporter) it gets some methods imported to its namespace. In my case, I was using Exporter in an abstract class to export some constants. I can go about this a couple of ways. I could have interface.pm look for a particular array in the interface class which lists base classes that are not to be searched. As an alternative, I could have it recognize Exporter specifically. The advantage to this last way would be that I could have it ignore things listed in @EXPORT_OK and other such variables. Now that I think about it, though… why would I want to do that? The real trouble is that constants are subroutine in Perl; so what I need is both a list (like @INTERFACE_IGNORED_BASE_CLASSES) to list base classes to be ignored on an interface as well as a list (like @INTERFACE_IGNORED_METHODS) to list methods in an interface that are to be ignored. Kind of messy but I can’t think of a better way to do it.

Had an exciting dinner tonight too. I’ll write about it in a while. Someone remind me.

November 8, 2002

Distractions

I started to code today, but many things distracted me. While thinking about my target, though (DarkWiki) it occurred to me that I will likely regret doing this in Perl, as this is no longer a small project. Indeed… I think I should abort it. I’ve come up with a good design, but I think it needs to be done in strongly-typed language, with a bunch of tests and other things. Admittedly, Perl does make things easy. I may forge ahead simply because of the week or two I’ve spent piddling with it.

One of my distractions was scheduling a roll-out of a two state, 13 site VPN-thingy for one of our clients. Scheduled in a couple of weeks. Firewall is on the other side of my bedroom wall. I’ll need to get that polished off. Supposedly the hardware will be ready come this Saturday or so… says my boss. So we’ll see how that goes.

Then I decided that I should try and use CPAN::shell to at least download CPAN distributions along with their dependencies. It turns out CPAN shell just isn’t well suited to this, as near as I can tell. Even CPAN.pm‘s documented API doesn’t have much to help me here. So what do I do? Go out and write some quick hackish stuff to do it myself.

WARNING! There are some links to some scripts I wrote today in the following paragraphs. I don’t really recommend using them. They’re not documented, highly untested — especially under any setup but my own — and liable to rm -rf /. Use at your own risk.

Anyway, it started with a way to use cpanflute2 (from the RPM-Specfile distribution) to quickly build packages the way I wanted them built. This turned in to buildcpanrpm. buildcpanrpm takes a CPAN distribution archive (or archives), copies (or moves with the --move-source option) the archive to your RPM SOURCES directory (it finds the “topdir” itself using rpm --eval — which isn’t in rpm(8) BTW), and then uses cpanflute2 to create the SRPM in the proper directory, and will optionally rebuild and install it. Common invocation for me might be buildcpanrpm --sudo-install Dist-File-1.0.tar.gz. --sudo-install tells it to use sudo rpm to install the binary RPM. It tries to make a guess of whether a distribution needs to be noarch or your default architecture (like i386), but it does this just by looking in the archive for *.xs files for now. This utility, like the rest, has no documentation. This utility, unlike the rest, has lots of options and could really use documentation. I suggest you look at the definition for @optionDescriptors in the source. (Ha.)

Then I wanted a way to find the dependencies of a module, since it was annoying to start building and watch for it to whine about missing pre-requisites. This became getcpanreqs. CPAN.pm seems to get the pre-requisites for a module by doing some parsing of the code in Makefile.PL itself to try and get the right value. While I’m sure that works pretty well, getcpanreqs does some extremely evil things and attempts to parse (some of) the code in Makefile.PL to get this value. I’ve had this fail already (on Time::HiRes) due to bad munging of the source, so use at your own risk. Just run getcpanreqs Some-Dist-1.0.tar.gz and it should spit out any required packages it finds, or a bunch of errors. On an implementation note for getcpanreqs: I look for WriteMakefile and take only code after that point. Should I just try parsing the whole file and hope for the best (i.e., nothing gets written, starts compiling, etc.)? Quite possibly. That’d take care of the parsing errors.

By now I’ve forgotten any good practices for coding I might once have known, so I say “hey, I’d like a script to download the distribution for a given module.” Then out of my ass popped cpandistformodule. You run it like cpandistformodule Foo::Bar and it gets the distribution file. (You can specify multiple modules.) You’ll have to edit this script to use it, and you’ll need the file 02packages.details.txt (possibly gzip’ed) from a CPAN mirror. You might also want to modify the URL in the CPAN_WGET variable to go to a different CPAN mirror. Sometime I’ll come up with a quick script to update 02packages.details.txt.gz. I got it by starting CPAN::shell for now.

So at this point I bet you can guess what I was thinking. Here I had a way to download a distribution for a module, get the required modules from that distribution, and build RPMs for a distribution. “darkness, darkness! Why not tie these together in an incredibly ugly shell script that’s bound to break horribly?” Yes! *thpprprptptttt* Out pops cpanget. You call cpanget like cpanget Some::Module Some::OtherModule and it combines the above three scripts to get that module and all its requisites, and even installs them. (In fact… it has to install them.)

These scripts are ugly. You’ll be in pain. Really, go play WC3 or TSO or something.

Almost forgot: these scripts need cpanflute2 as mentioned above, as well as Archive::Tar and Compress::Zlib. And don’t try running getcpanreqs on them or something stupid like that (it only looks at Makefile.PL from a distribution).

Tomorrow maybe I’ll actually get some coding done. Oh, BTW, Log4perl looks even cooler than Log::Config::Dispatch. Check it out if you want logging stuff in Perl.