I spent about 2 hours tonight trying to figure out why my modal dialog box refused to work under Internet Explorer 6.0. The symptom was that in addition to the rest of the webpage being grayed out, the modal box was also being grayed out. Not good.
The culprit turned out to be this bit of CSS:
Having the position set to "fixed" will screw you every single time. (Plus, the box displaces your page content, instead of appearing over top of it, like you would expect with a high z-index value.)
The fix is to change the position attribute from fixed to absolute. Once you do that, it behaves as expected in both MSIE 6 and FireFox.
Other than that little problem, the jqModal library is a nice little library which can create pop-up boxes within a webpage that are part of the same window. It can also "gray out" the current contents of the page and force the user to click in the box before continue. Very handy to have, if you want to make the user agree to the T&Cs of a particular website.
The problem
After I brought Anthrocon's room share and ride share forums online, I noticed that last year's posts were still present. This was a problem because people needing rides or rooms for this year's conventions did not notice the date and were replying to those posts, thus wasting everyone's time.
Now, I dislike removing content from any website I manage, since that can potentially hurt Google's PageRank on the site. If only there were some way of removing the old posts from those forums without actually deleting the posts...
Then I remembered that Drupal's database is in third-normal form and came up with this query after about 15 minutes of fiddling:
CREATE TABLE temp_nids (nid INT(10) UNSIGNED);
INSERT INTO temp_nids (
SELECT nid FROM term_node WHERE nid IN (
SELECT n.nid FROM node AS n
LEFT JOIN term_node AS tn ON n.nid=tn.nid
LEFT JOIN term_data AS td ON tn.tid=td.tid
WHERE td.name IN ('Room Share', 'Ride Share')
AND FROM_UNIXTIME(n.created) < '2007-08%'
)
)
DELETE FROM term_node WHERE nid IN (SELECT nid FROM temp_nids);
The innermost query (SELECT n.nid FROM node...) selects node IDs that belong to the Room Share or Ride Share forums with a creation date before August, 2007. The query around that (SELECT nid FROM term_node...) I originally had in to make sure that we got valid node IDs from term_node. Given how the query evolved, that's probably no longer necessary. The outermost query (INSERT INTO temp_nids) stored the matching node IDs in our temporary table for later use.
The final query (DELETE FROM term_node...) deletes the offending node IDs from the term_node table, which is responsible for linking nodes to taxonomy terms.
In other Drupal news, I stumbled across a nice little article the other day called 10 Reasons to Use Drupal CMS. While I knew some of the things mentioned in that article, I had no idea that entities such as The United Nations, Forbes, The Discovery Channel, AOL, and most surprisingly of all--The Grateful Dead.. all use Drupal. Fascinating stuff.
Also, I found the website Drupal Dojo which contains lots of tutorials on how to perform different tasks in Drupal. It looked just like another how-to type site (not that there's anything wrong with that!) until I came to the article on patch rolling and saw this:
Um, yeah... I sure wasn't expecting to see that particular graphic. 
I flew out to Chicago on Friday night to visit some folks for the New Year's .
The flight out was fun, as Chicago got quite a bit of snow that day and was all backed up. So we sat in Philly for about an hour, then after we landed we got to sit around some more until a terminal and a ramp were freed up for us. The entire story is chonicled in my Twitter. I have vague memories of meeting Duncan and Takaza at the airport sometime after midnight and not getting to bed until WAY too late that night. 
I then spent the rest of the weekend at Wuffmeet, having 3 solid days of fun, and returned home last night. At some point during the trip, we headed over to The Westin in Chicago. It is a really sweet hotel and I think it will make a fine venue for Midwest Furfest in 2008.
I don't have much to say about 2007 other than that it was a very positive year. Many aspects of my life just got better and better, and I saw some good things just continue to build on themselves. I guess you could say it is a kind of compound interest, if you will. A few high points that stick out:
- Paid off the last of my student loans
- Sold my car. This helped my cash flow quite a bit, and was a great way to say "screw you" to both the auto and oil industries.
- Got a Pro Account on Flickr and uploaded over a thousand photos. Photography has always been a hobby of mine, and Flickr made it very easy for me to share this with others.
- Attended a number of furry conventions and got to do a fair amount of traveling.
- Saw that I was starting to gain weight and was able to reverse that trend after paying more attention to what I ate.
- Went to the beach for the first time in several years.
- Opened an account with Vanguard and took more control over my retirement funds. (Ameriprise's website is just awful)
I haven't yet had a chance to upload my pics from either The Westin or Wuffmeet. I'll try to do that tonight.
Today's programmatic venting is brought to you by Internet Explorer's implementation of the setTimeout() function under Javascript.
What is setTimeout()?
setTimeout() schedules an arbitrary function call for some point in future. This is useful when you have functions that do repetitive tasks some milliseconds apartment, but not constantly.
The reason why this is used instead of a simply while (true) { ... } loop is because Javascript is a single-threaded language. So if you tie up the interpreter by executing one piece of code over and over, nothing else in the browser gets a chance to run. setTimeout() allows other pieces of Javascript (or browser events, such as clicking on a button) to run, while guaranteeing that your code will be executed at some point.
Sounds cool. How do I use setTimeout()?
Simple, like this:
setTimeout(function_name, msec);
This will cause a function called function_name to execute a certain number of milliseconds in the future.
For functions that don't need data passed into them, that works great. But what if you want to pass in parameters? In FireFox, you would do this:
setTimeout(function_name, msec, arg1);
And this works great. It will call the function called function_name again in the specified number of milliseconds. Except, MSIE doesn't like this. And rather than throw an error, it just ignores the additional arguments. So when function_name gets called again, its argument is now undefined, and choas ensues.
[Edit: It has since been pointed out to me that the most recent draft of the spec does not allow for additional parameters to setTimeout(). Okay then, but why isn't MSIE at least throwing an error? Silently accepting additional arguments and then just throwing them away is just plain stupid.]
So how do I work around this annoyance?
Closures. Up until now, I thought that closures were very geeky, and used only by CS people who were working on their PhDs. Then I saw this:
setTimeout(function() {function_name(arg1)}, msec);
Wait, what? What's going on there? Well, it might be a little easier to understand if I write it like this:
var f = function() {function_name(arg1); };
setTimeout(f, msec);
What's happening there is a variable called "f" is created, which is actually an anonymous function. That function in turn contains a single line of code:
function_name(arg1);
A call to the function we really want to call, with our specified argument. Note that all we have done so far is define a function that calls our target function. We have not executed either that function or the target function -- the target function is essentially "frozen in time". This is a very important concept, and if you've never done this before, you will have difficulty wrapping your brain around it. 
To get a better idea of what's going on, in this case, you could also execute the variable f as a function, since it now *is* a function for all intents and purposes:
f();
Bringing this all together, in the above example, the end result is that the function function_name will be executed after the specified interval, with the desired argument. And this will work in both MSIE and FireFox.
Just out of curiosity, what is a practical application of this function?
I'm glad you asked! As I mentioned above, Javascript is single-threaded. This means that a loop that takes a long time to run can cause the browser to appear to "freeze up" or become unresponsive, which detracts from the overall user experience. A perfect example of this would be populating a div with rows of data retrieved via AJAX. Writing 1,000 rows into that div takes about 3.2 seconds on my machine, during which the browser will not respond to commands.
What I did in my little test was instead of printing each row as it was retrieved, I instead stored them in an array. I then wrote a function which shift()ed and printed only 50 elements from that array. After 50 elements were printed, it then checked to see if there were any elements left in the array. If there were, it would call setTimeout() with itself and the array inside a closure, to be run again in 10 millseconds. The end result took a little longer, 3.5 seconds, but resulted in a much more responsive browser, and happier users.
Share and enjoy!
Source: Passing parameters to a function called with setTimeout, by Bryan Gullen
Welcome to my blog!
To tell you the truth, I do most of my blogging over on LiveJournal, because most of my friends hang out there.
But I still make occasional blog posts to my website, especially when it's something which I feel is important, or was particularly well received by folks over on LJ.
Public service announcement time, folks.
If you keep shouting about negative stereotypes of furry fandom and "that's not what we're all about", well... all you're doing is bringing attention to those stereotypes. They'll still be associated with furry, regardless of what you as an individual do. Right now, we are doing a better job at promoting negative stereotypes about ourselves than any troll could ever hope to do.
Wanna do something productive? Try talking about positive aspects of the furry fandom. Mention how nearly every convention is a non-profit, how furry conventions have raised tens of thousands of dollars for charity, talk about some of the cool fursuits, or some other positive way that furry has impacted your life.
We can't control the trolls. But we can control ourselves, and what we say. Let's make the most of it.
Since Furry Connection North is a first year con, they've been relying on the generosity of staff to loan the convention money. They'd like to repay them ASAP, but furs generally don't register until the month before a convention actually happens. They're getting some registrations, but to encourage more, they've organized a promotion.
The first 25 people to register will be put into a raffle to be given a free upgrade to Pimp status! (If the winner registered as a Pimp, they'll get a $25 refund.) This includes cash, check and credit card registrations, so however you register you can participate. So go to http://furryconnect.com/registration.php and register with your credit card, get the form to mail in a check, or give Nikvulper or girtygrin cash and a printed out form at a furmeet.
Good luck, and I'll see you at the con!
So, awhile back I wrote about external hard drives, partly because I was interested in performing backups. I also noticed some speed increases when I did backups to my external hard drive, so I decided to look into performing regular backups onto it in additional to the semi-regular backups I do onto DVDs.
Why back up to an external hard drive?
I don't have to waste a DVD every time perform a backup, especially if I am making backups on a daily basis. Plus, the same amount of data can be backed up to my external hard drive in less time.
Note that I still back up to DVDs, since those are more durable and can easily be taking offsite. But those backups are done every few weeks at best, so backups to my external hard drive are done more frequently -- usually every few days.
What is backed up?
Various documents, my photography (I take a lot of pictures), source code for projects I am working on, my Moneydance financial data, and tarred/gzipped backups of websites that I manage.
What is not backed up?
Any movies and music that I have--since those files are static (i.e., they never change), I just burn them to DVD when I have enough content to actually fill a DVD. There's simply no need for me to keep backing them up over and over. Sure, it's nice to have multiple copies of this stuff, but I simply do not have that much of a need for my MP3s. (And it's not like I can't rerip them from my CD collection) Any pictures that are older than a year old are also burned to DVD and removed from my Pictures/ directory, since I am no longer working with them on a day-to-day basis.
So, I got a turkey sandwich from Wawa tonight, and asked for pickles on the side.
Oh, did they ever give me pickles...
I had a blast at FurFright 2007 last weekend. As far as cons go, it was a little different for me, because it was the first furry con where I worked security. So I didn't have the opportunity to visit much programming at the convention. I did however, have plenty of time to hang out with folks that I knew, as well as meeting a few new people.
One fun thing about working security is that this guy had to work for me:
I made sure to remind him of this often. 
Uncle Kage's parents were also in attendance:

Both Grandma Kage and Grandpa Kage got to work security, and it was great to see them again.
Freddy Krueger made an appearance. Sort of:
We also had our usual amount of prey animals present. The fact that their upper hooves were bound made it much easier to get a meal:
We also had at least one warrior fox present:
This was the first con that I used PhillyCarShare to drive to and back. That worked out rather nicely. Since PCS does rentals by the hour (with a daily rate), I was able to get a car from 6 PM on Thursday to 9 PM on Monday, and not have to pay the ridiculous hourly charges that AVIS would have hit me with. The total cost of renting the car was about $250, which included mileage. That was comparable to what I would have paid for a rental from AVIS. [1] For GPS, instead of renting one from AVIS for $9.95/day, I instead used the GPS on my new phone. That worked out just as well. So I'd say that using PhillyCarShare to get to the con and back was a success!
Finally, if anyone wants to see my entire archive of pictures, they can be found at: http://www.flickr.com/photos/dmuth/sets/72157602708286153/
Enjoy!
[1] Keeping in mind that I would have had to purchase ALI (Additional Liability Insurance) from AVIS, since I discontinued my car insurance after selling my car. That is $12.95 a day. With PhillyCarShare, they provide insurance -- a $1 Million policy, for all drivers.