October 2006 Entries

CAPTCHA For Trackbacks

Jeff Atwood points out several problems with using blacklists (specifically Akismet) to prevent comment spam.  He makes the following point:

The core problem is relying on a single method of defense against spam.

Absolutely.  Subtext employs several measures against comment spam, mostly of a heuristic nature.  The latest release adds Akismet support as well as Visible and Invisible CAPTCHA.

The funny thing about CAPTCHA and especially Invisible CAPTCHA is the number of people who claim it won’t work and is broken. As Jeff points out, this may be true among researchers, but it is not the case in the wild.  However let me back up his post with some numbers.

For the past four days, I have not emptied my blog spam folder, just to see what gets put in there.  So far, in that time, my blog has received 1441 comments, trackbacks, etc...  Of those, 1407 have been flagged as spam by Akismet or marked as spam by me.  Of those, only one was a comment.  The rest were trackbacks/pingbacks.

So as far as I am concerned, Invisible CAPTCHA is working well so far.  And it has the benefit of being usable, assuming you can do simple math.

So assuming that CAPTCHA, for now, is the best approach to fighting comment spam, we need to deal with its critical weakness.

The real problem is how do we enable CAPTCHA for trackbacks?

I wrote about this problem before when I discussed my qualms about CAPTCHA.

The reason I didn’t mention CAPTCHA is that it would be ineffective for me.  Much of my spam comes in via automated means such as a trackback/pingback .  The whole point of a trackback is to allow another computer to post a comment on my site.  So telling a computer apart from a human in that situation is pointless.

I mentioned this to Atwood who pointed out that trackbacks and pingbacks are indeed automated, but they are left on behalf of a user.  This is true.  When I write a blog post, Subtext will look at all the links in my post and attempt to trackback each one for me.

Unfortunately, the trackback and pingback APIs have no facility for dealing with CAPTCHA. Unless there were a community effort to revise these specs (I would be happy to join in), CAPTCHA for trackbacks and pingbacks are not gonna happen.

Even with such a community effort, implementing CAPTCHA for trackbacks is going to be a lot of work for blog implementers.  In part, this is indicative of a usability issue with CAPTCHA based approaches.  CAPTCHA requires human intervention.  This makes integrating CAPTCHA with something like trackbacks hard work, whereas if someone comes up with a better automated filter, integrating that is easy.

So for the time being, we have two choices.

  1. Abandon Trackbacks/Pingbacks
  2. Find better ways to filter trackbacks and pingbacks.

I know many have decided to simply abandon trackbacks.  I understand this choice, but I personally am not ready to throw in the towel just yet.  Trackbacks can and do add a lot of value to discussions that occur via blogs.  So far, Akismet has allowed me to reclaim trackbacks.

What is the next step? Well I agree with Jeff:

Akismet is a fine addition to our anti-spamming toolkit. But that doesn't mean it's a good idea to outsource your entire anti-spam effort to a single website, either. Anti-spam security starts at home. For best results, use defense in depth and combine local anti-spam measures, such as CAPTCHA, with Akismet as a backup.

Though I think we need to start working on some better non-CAPTCHA filters to combine with Akismet.

Happy Halloween

I love Halloween because it makes for great parties. What makes a party great? Costumes! This past weekend I drove up from Los Angeles to San Jose to stay with my friend Kyle and his wife Cara. That evening we drove up to San Francisco to attend a house party in a large four story house in the hills. It was about the perfect size for the 100+ people in attendance, and they hade a few top-notch local DJs spinning.

Unfortunately, I didn’t bring my camera so I had to rely on “donated pics”. I usually am a total shutterfly. Of course, not having my camera gave me more time to enjoy the party. Click on a pic for a larger version.

Hunter S. Thompson and Noam Chomsky Group of people outside the house

My buddy Kyle went as Noam Chomsky, which was a hit of a costume, as simple as it was. It’s rather freaky to see a black and white 2-D face on a normal body. The face looked almost disembodied. The first pic with Hunter S. Thompson just cracks me up. What a literary powerhouse! I went as the thoroughly unimaginative “Kung-Fu guy”. The necklace I’m wearing is made up of miniature skulls of my enemies. Yes, I fight those crazy Lilliputians.

The DEA agent was probably one of my favorite costumes, just for the chill he sent down the spine of some partygoers.

Steve Irwin, the Crocodile HunterCartman and Snack

As expected, someone with showed up in a Crocodile Hunter costume, though I don’t understand the red wig. We also had Cartman and his favorite snack in attendance.

Inside the party The Governator

Finally, the governator showed up, but he was inappropriately dressed. I had to black out that portion of his costume. Let’s just say, it took a pretty big circle to black that portion out. Good going Guv’nor!

BeakerCount Pimpula and Cheerleader

The beaker costume above was one of my favorites.  She and her boyfriend both were beakers. Apparently the sight of them making out was disturbing.  That’s my friend Jason aka Count Pimpula on the right with his girl Rocel.

Another Subtext 1.9.2 Upgrade Bug

Steve Harman points out another bug in the upgrade process.  I feel really terrible that this one slipped through, though as far as I can tell so far, it may be mostly cosmetic in its effect.  It apparently converts some comments to trackbacks.  While this is not desirable behavior, since we show both comments and trackbacks in the comment section, it might not have a huge negative effect.

Unfortunately, I am in San Jose right now, so I can’t update the release with a fix yet. Hopefully Steve can handle it. Smile

Insomniac Thought Of The Evening

Cheese Image Source: http://www.newsday.com/news/columnists/ny-fdwinecheese,0,4672893.photo?coll=ny-rightrail-columnistActually yes, I would like a little cheese with that whine.

What Feature Should Be Removed?

In the essay entitled Hold the Mayo, 37signals points out the obvious fact that most surveys ask users what features they want added to a product.  They rarely ask what features they want removed.

I have in the past asked users for permission to remove features, but I've never taken the extra step of asking users, which features would they like removed.  So here I go. 

Which feature(s) would you like to see removed from Subtext?

I think a natural response I will receive is the question, Why would you ever want to remove a feature?

Features have many hidden costs.  Even relatively simple features.  I am going to tell a short story about one such occurrence that happened in Subtext.  I won't name names and this is not meant to call anyone out for public embarrasment or chastisement.  I have probably been more guilty of this than anyone.

Not too long ago, someone checked in a control into Subtext that displays recent comments, just as we were close to preparing a release.  I was a little miffed at the time because I was not expecting anyone to add features at the time.

However this was a pet feature and some of the devs really wanted it in the system.  Besides, it's such a small feature, what could go wrong?  So I let it in not wanting to be a hard-ass about it.

The recent comments control is a pretty simple control in concept.  When added to the main skin template, it simply displays recent comments left on various blog posts.  Sounds simple, no?

However, as with any feature, the devil is in the details.  Several problems immediately became apparent as we tested the release, and one problem affected me in a later release.

  1. The control let you truncate comments after a certain number of characters.  However it didn't strip HTML out, so if it truncated a comment in the middle of a tag, it would completely mess up the whole page.
  2. The control bypassed our provider model and made stored proc calls directly.
  3. The control displayed all feedback for a blog, even ones that were left via the Contact Page, thus potentially displaying private messages.
  4. Recently, I tried to append a little HTML comment after messages that had been processed by Akismet to make it easy to see that Akismet was indeed working by viewing source.  Comments aren't being stripped by the Recent Comments control, so the site was broken in a way that I had not anticipated. It took a long time before I realized what was happening.

So for a relatively small feature, a lot of development time and effort was used up in supporting it.  I am glad we have the feature now, I really like it and plan to add it to my own blog at some point.

But the main point still stands, every feature is like an iceberg. When scoping it out in your head, you typically only think of the top part that sticks out above the water.  However, the real effort is in the part under water that supports the whole thing.

Iceberg Photo from http://shiftingbaselines.org/blog/archives/2005_02.html

So if there is a feature in your product that provides very little bang for the support buck, consider getting rid of it.

So again, Which feature(s) would you like to see removed from Subtext?

Getting Real

Getting Real Now that 37signals have put their book Getting Real online for free, I’ve finally gotten around to start reading it. And so far, I love it. I think there are a lot of great lessons, reminders, ideas in here that will help me make products I work on that much better.

I have a premonition, even before writing this, that a lot of people will tell me that the book is crap because they don’t believe in functional specifications and even Joel believes in functional specifications. As the authors point out in their Caveats, disclaimers, and other preemptive strikes page, their techniques don’t apply to everyone (though probably to more people than one would think). Also, their ideas are not an all or nothing affair. Gotta have your functional specs, then by all means keep doing it. Don’t throw out the baby with the bathwater.

Open Source projects are probably in the best position to make use of their guidelines, though I am sure many more projects would be made much better by getting real. Subtext will most certainly gain from many of these approaches. My hope is to use Subtext as a testing ground for the principles in Getting Real, and then using its success to show my clients that they don’t need to be so rigid about product development. We’ll see.

As you might guess, many of my upcoming blog posts will focus on some of these topics.

Subtext 1.9.2 Bugfix Update

As I mentioned in my last post, someone reported a bug with deleting posts in the admin tool.  That posts also describes a quick and dirty workaround.

However, I fixed the bug and updated our current 1.9.2 release at SourceForge.  The existing URL to download the release is still valid.  The full version number for this release is 1.9.2.23.

To find out which version of Subtext you are running, just log into your admin and look in the bottom left corner.  You should see the version there.

Subtext Version

If you downloaded Subtext 1.9.2 before I applied the update, then you will probably see version 1.9.2.19 in there.  If so, you have two options.  You can either apply the quick and dirty patch mentioned in my last post, or you can download the latest build and update the Subtext.Framework.dll file in the bin directory.

However, this latest update also includes some CSS fixes for the KeyWest skin in IE 7 designed (and fixed) by Robb Allen.  So if you are using that skin, you should download and apply this update.

Tags:

PATCH: Cannot Delete Posts In Subtext 1.9.2

Someone reported that they cannot delete posts in the just released Subtext 1.9.2. I am mortified that we do do not have a unit test for this function!  To our defense, we did start with 0% code coverage in unit tests and have now reached 37.9% and rising!

I have a quick fix if this problem affects you. I am also currently building a more permanent fix which I will release soon.

Run the following query in Query Analyzer (don’t forget to hit CTRL+SHIFT+M to replace the template parameters before executing this).

ALTER PROC 
    [<dbUser,varchar,dbo>].[subtext_DeletePost]
(
    @ID int
    , @BlogID int = NULL
)
AS

DELETE FROM [<dbUser,varchar,dbo>].[subtext_Links] 
WHERE PostID = @ID

DELETE FROM [<dbUser,varchar,dbo>].[subtext_EntryViewCount] 
WHERE EntryID = @ID

DELETE FROM [<dbUser,varchar,dbo>].[subtext_Referrals] 
WHERE EntryID = @ID

DELETE FROM [<dbUser,varchar,dbo>].[subtext_Feedback] 
WHERE EntryId = @ID

DELETE FROM [<dbUser,varchar,dbo>].[subtext_Content] 
WHERE [ID] = @ID

GO
SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

GRANT  EXECUTE  ON 
 [<dbUser,varchar,dbo>].[subtext_DeletePost]  
TO [public]
GO

Sorry for those that this affects. Like I said, we’ll have a bug fix out soon.

Tags:

What Do You Do If You Find A Wallet?

Wallet Well if you’re the punk malcontent who found my wallet yesterday, you go on a shopping spree...at Rite Aid, Vons, and Ralphs (a convenience store and two grocery stores). 

Really, if you’re going to try and spend my hard-earned credit, at least go buy something decent like a stereo system.  There’s a Best Buy just down the street that isn’t much further away than the local Vons.

I mean who spends $103 at a Rite-Aid?!  Who!?  I really mean it. Who? I’d like to know because I want my wallet back.  And to the store clerks there, doesn’t it even slightly ring the suspicion bell in your head when someone tries to buy $103 worth of anything at Rite-Aid?  I didn’t even know you could buy that much stuff at a Rite-Aid. I figured buying out everything in the store would lighten your wallet by about $70, tops.  Maybe he bought the cash register too.

Did you even look at the guy and compare his picture to the Id, my Id, he presented?  There’s not a lot of hapas running around L.A. so I doubt he looked that much like me, assuming it was a "he".

Anyways, yesterday on a short walk, I dropped my wallet.  A really comical mistake like you see in the cartoons. I put my wallet in my side cargo-short pocket, which unbeknownst to me, had a huge gaping hole in it.  I returned back to the area literally 10 to 15 minutes later, and it was gone.  And then the charges started showing up in my account as I frantically called to close my cards.

Anyways, that’s why I rushed out a new release of Subtext last night.  I figure follow something bad with something good.  Oh, and I bought a lottery ticket.  I know, the chances are pretty much nill. But what were the chances I’d put a wallet in a pocket with no bottom?  This is a chance for the world to get back to even terms with me. Wink

Insomniac Thought For Tonight

Chameleon Having trouble sleeping lately. Thought I'd start an intermittent blog series about the questions that keep me up at night.

For example, this question popped in my head tonight and would not let me rest.

What the hell is a Karma Chameleon?

Ponder amongst yourselves.  I bid you adieu.

Essential Subtext 1.9.2 Crib Notes

UPDATE: A bug was reported that blog posts could not be deleted. We have updated the release files with a fixed version.  There’s also a quick and dirty workaround.

Reading over my last blog post, I realized I can be a bit long winded when describing the latest release of Subtext. Can you blame me? I pour my blood, sweat, and tears (minus the blood) into this project.  Doesn’t that give me some leeway to be a total blowhard? Wink

This post is for those who just want the meat. Subtext 1.9.2 has the goal of making the world safe for trackbacks and comments.  It adds significant comment spam blocking support.  Here are the key take-aways for upgrading.

  • As always, backup your database and site first before upgrading.  We implemented a major schema change which requires that the upgrade process move some data to a new table.
  • If you are upgrading from Subtext 1.5 or earlier, read this.
  • Instructions for upgrading.
  • Instructions for a clean installation. This is easier than upgrading.
  • When upgrading, make sure to merge your customizations to web.config into the new web.config.
  • If you use Akismet, make sure not to use ReverseDOS until we resolve some issues.
  • After upgrading, login to the admin and select the correct timezone that you are located in.

Download it here.

Subtext 1.9.2 "Shields Up" Edition Released!

Making the world safe for trackbacks again!

UPDATE: A bug was reported that blog posts could not be deleted. We have updated the release files with a fixed version. There’s also a quick and dirty workaround.  You only need to apply the fix if you downloaded and installed Subtext before this update message was posted.  See here for details.

Well it took me a little longer than anticipated, but I finally teased out the remaining show stopper bugs and put the finishing touches on Subtext 1.9.2. If you plan on upgrading to Subtext 1.9.2, please consider reading this entire post carefully. If not, at least remember to backup your database and site first before upgrading!

What happened to 1.9.1? Long story for another time. We are skipping from 1.9 to 1.9.2. Here is a list of releases so far just in case you were curious. UPDATE: I had only listed the versions that required an automatic upgrade. Here is the complete list with the ones in bold required an automatic database update:

  • Subtext 1.0
  • Subtext 1.5
  • Subtext 1.5.1
  • Subtext 1.5.2 
  • Subtext 1.9
  • Subtext 1.9.2

As you can see, our version numbering has been a bit less than consistent. But starting with 2.0, we should stay a bit more consistent. With the launch of IE 7, don’t be surprised if we come out with a 1.9.3 version that just includes fixes to the skins. Volunteers for that effort are welcome.

New Features

The reason we call this the “Shields Up” edition is that the focus has been on dealing with Comment Spam. I had few interesting ideas I could not implement in time, but I did implement three key features that have really made a huge difference in regards to comment spam, and may not necessitate my other ideas.

Akismet Support

Subtext now has full integrated support for Akismet spam filtering. Not too long ago, I released an Akismet API so that others can use it for spam filtering. Scott Hanselman Members of the DasBlog team implemented it for DasBlog (in their source control tree. Not yet released.) and has nothing but praise for it, saying it has completely eliminated comment spam for him.

Now let me explain what I mean by full integrated support. When you enable Akismet and are looking at approved comments in the feedback section, if you notice something that should have been filtered as spam, you can check it and click the Spam button. That will then report a false negative to Akismet, indicating that they failed to mark this item as spam and then move the item to the new Trash folder.

Likewise, if you notice an item that is flagged as spam, but should not have been, you can check the item and click Approve which reports a false positive to Akismet. By doing so, you will be training Akismet to become more adept at filtering spam.

Note, to enable Akismet, you must sign up for an Akismet API key and supply that key to Subtext via the admin section. In order to get this key, you have to register for a Wordpress.com user account, whether or not you plan to use a Wordpress blog.

Another note, Akismet may not work in Medium Trust scenarios. So if you host your site with a hosting provider such as GoDaddy, WebHost4Life, etc... who run their sites in Medium trust, Akismet might not work for you. I wrote about the problem here.

In the comments to the aforementioned post, Scott Watermasysk points out a promising approach. Have your hosting provider set up a proxy which can be used to make requests. To that end, I did add some Web.config appSettings for enabling proxy support: ProxyHost, ProxyPort, ProxyUsername, ProxyPassword.

If specified, all web requests for subtext will use this proxy.

Invisible Captcha

Not too long ago, I released a lightweight invisible CAPTCHA validator control. As far as I can tell, it has worked pretty well at keeping out automated comment spam. But as I also warned, it did nothing to stop Trackback/Pingback spam. Hence the need for Akismet support.

Invisible CAPTCHA is probably not necessary given the Akismet support, but since Akismet is not enabled by default and Invisible CAPTCHA is, it will provide some relief until you get your Akismet API key, if you so choose.

If Invisible CAPTCHA causes problems for you for some reason, you can turn it off for the entire site (no per-blog setting) via Web.config.

Visible CAPTCHA

Some of you twisted my arm, so I am complying. I love my users so I gotta keep them happy. We now have support for the standard visible CAPTCHA you know and love.

Time Zone Fix

This topic gets its own special treatment because it is both a bug fix and a new feature. Not too long ago I mentioned some work I did for DasBlog regarding daylight savings time.

Long story short, there was no way in the .NET framework to convert from one arbitrary timezone to another. The way this manifested in Subtext is that users who had their blog hosted in another timezone always had incorrect timestamps on their blog posts.  This fix resolves that issue.

Previously, Subtext only stored a timezone offset for each timezone. For example, the offset for Pacific Standard Time (PST) is -8. However that is not accurate enough to be correct. For example, at the time of this blog post, the offset is actually -7 because of Daylight Savings Time.

Likewise, choosing -7 for a timezone is not accurate because Arizona does not observe daylight savings, but Mountain Time does. The only way to really get this accurate is to store the actual timezone and not just the offset. So that is what Subtext now does.

We now list every timezone (at least every one I could extract from the Windows XP registry). There is no natural integer identifier for a timezone, so based on a suggestion by someone at Microsoft, I used the hash code of the timezone’s Standard Name. This is the only guaranteed consistent unique identifier for a timezone. So when you upgrade to 1.9.2, we try and update your offset to the most likely timezone id. Obviously, we can’t be perfect about this, so after you upgrade, you probably want to login and configure your blog with the correct timezone if we chose unwisely.

Other Release Note Items

  • Feature [1565237] Support referencing External CSS
  • Feature [1577073] Flag All, Destroy All options
  • Fixed [1584075] Disabling trackbacks didn’t disable trackbacks properly.

Upgrade Instructions and Warnings

If you are upgrading from Subtext 1.5 or below, then please read this important note on upgrading. Subtext 1.9.2 runs on ASP.NET 2.0, so upgrading from 1.5 and below(which ran on ASP.NET 1.1) takes a few additional steps than normal.  As always, don’t forget to merge your web.config customizations into the new web.config file.

Also, for all people upgrading to 1.9.2. The Subtext 1.9.2 upgrade process performs a major database schema change, moving all comments and trackbacks into a new subtext_Feedback table. We’ve tested this over and over again working out all the kinks we could find, but we can’t guarantee that it will be 100% perfect. Thus backup your database first before upgrading!

Also, as I mentioned in the previous section, after you upgrade, please check the timezone setting in the admin section.

Lastly, in order to improve the commenting experience, we’ve added a tiny dash of Ajax using the MagicAjax control for leaving comments on a blog. However, this does not work well with the excellent ReverseDOS because ReverseDOS acts before the request is passed on the our code. If you plan on using Akismet, it is recommended that you turn off ReverseDOS support in the Web.config. In fact, the web.config file that comes with 1.9.2 disables ReverseDOS. I’ve been in contact with the ReverseDOS creator, Michael Campbell, about these issues and he has plans to work together to address them. But like all things, life comes first.

Even though Akismet does a great job with comment spam, I still think ReverseDOS is worthwhile and a nice complement to Akismet. However, we need tighter control of when ReverseDOS is triggered in the request pipeline in order to integrate it into Subtext’s existing spam filtering functionality.

Download

Ok, enough talk already, where do I download this sucker?  The download is hosted by SourceForge here: [DOWNLOAD]

SearchDotNet.com

Dan Appleman takes the .NET focused custom search engine idea one step further by grabbing a great domain name for his search engine.  Now why didn’t I think of that!  Sometimes that’s all it takes between a search engine that will get used alot (his) and one that won't (mine).  I'd be happy to throw my support over to his, though I’m keeping my baby.  The one key difference is I plan to leave my search engine open for others to contribute sites.  Perhaps the two will complement each other.

And no, the domain name is not the only reason. This guy *is* Dan Appleman after all! He wrote the Visual Basic Programmer's Guide to the Win32 API which allowed me to feel like a real programmer despite using VB back in the day.  For this, I owe him a debt of gratitude as I was thus equipped to stand up to the C++ snobs.

Now we just need someone to help spruce up the logo.

Tags: , , ,

Integrate Your Custom Search Engine With The Browser

In response to question about integrating my custom search engine with the browser, Oran left a comment with a link to a post on how to implement searching your FogBugz database in your browser via the OpenSearch provider, which is supported by Firefox 2.0 and IE7.

So I went ahead and used this as a guide to implementing OpenSearch for my custom search engine on my blog.  When you visit my blog, you should notice that the the search icon in the top left corner of your browser is highlighted (screenshot from Firefox 2).

Open search box.

Click on the down arrow and you will see my own search engine Haack Attack in the list of search providers.

Haack Attack

Now you can search using Haack Attack via your browser.  Implementing this required two easy steps.  First I created an OpenSearch.xml file and dropped it in the root of my website. Here is my file with some of the gunk removed from the url.

<?xml version="1.0" encoding="UTF-8" ?>
<OpenSearchDescription 
    xmlns="http://a9.com/-/spec/opensearch/1.1/">
  <ShortName>Haack Attack</ShortName>
  <Tags>Software Development C# ASP.NET</Tags>
  <Description>
    Search the web for relevant 
    .NET and software development content.
  </Description>
  <Url type="text/html" 
    template="http://www.google.com/custom?
    StuffOmitted&amp;q={searchTerms}" />
</OpenSearchDescription>

Remember to make sure to use &amp; for query string ampersands, as this is an XML file.  Also, if you are using your own Google Custom search engine, the actual template value looks something like:

http://www.google.com/custom?cx=016071428520527893278%3A3kvxtxmsfga &q={searchTerms}&sa=Search&cof=GFNT%3A%23000000%3BGALT%3A%23000066% 3BLH%3A23%3BCX%3AHaack%2520 Attack%2520The%2520Web%3BVLC% 3A%23663399%3BLW%3A100%3BDIV%3A%23336699%3BFORID%3A0%3BT%3A%23000000 %3BALC%3A%23660000%3BLC %3A%23660000%3BS%3Ahttp%3A%2F%2Fhaacked%2Ecom %2F%3BL%3Ahttp%3A%2F%2Fhaacked%2Ecom%2Fskins%2Fhaacked%2Fimages%2F Header%2Ejpg%3BGIMP%3A%23000000%3BLP%3A1%3BBGC%3A%23FFFFFF%3BAH%3Aleft& client=pub-7694059317326582

So be sure to change it appropriate to your own search engine.

The second step is to add auto-discovery. I added the following <link /> tag to my blog.  The bolded sections you would obviously want to customize for your own needs.

<link title="Haack Attack" 
  type="application/opensearchdescription+xml" 
  rel="search" 
  href="http://haacked.com/OpenSearch.xml">
</link>

So give it a try and let me know what you think. Be sure to add sites you think are relevant to this searh engine.

My Very Own Search Engine

Google Beta Google just launched a neat build-your-own-search-engine feature.  You can choose sites that should be emphasized in the search results, or even restrict search results to that list.

It offers a lot of customization, but I seemed to have run into a problem in which it doesn’t seem to be saving the images for my profile for some reason. 

One particularly neat feature is the ability to allow others to collaborate on the search engine.  For example, check out my search engine called Haack Attack the Web.  I entered a few .NET and software development focused websites to the list of sites to search, restricting results to just those sites.

Feel free to add your favorite websites to the search engine.  I think I’ll actually find this as a useful first stop for finding .NET content.

The next step is to integrate this into the search features for Firefox and IE7.  Anyone want to help?

The Viper Room And Soccer Woes

The Viper RoomLast night I went to the “World Famous Viper Room”.  Gotta respect that their website makes sure to mention the World Famous part.  I suppose you’d have to have a real club inferiority complex to promote your club as The In This Neighborhood Sorta Famous Viper Room.

Anyways, the purpose of my visit was to see my soccer (sorry, football) teammate and team captain Pete perform in the acoustic lounge, an intimate (read tiny) lounge downstairs from the main room.

Pete’s the one from Glasgow with a heavy Scottish brogue.  We can hardly understand him most of the time, though I'm getting better at it.  Usually I just nod my head in agreement.

After our last game we asked Pete if he’d get us on the guest list.  “Not after that performance I won't.” was his reply...I think.  He was referring to the 12 to 1 drubbing received at the hands of Hollywood United.  This is the team fielding 9 internationally capped players and two World Cup players, one of whom was on the winning squad of the 1998 champions.

In contrast, we are fielding one internationally capped player who played for the Cayman Islands.  We should be making some acquisitions for the next season that should help.  Our goal for the next season is to keep them in the single digits.  Incremental improvements, ya know?

Mapping Drives Via Remote Desktop

Here’s a little trick that I didn't know about till Steve told me about it.  So that’s what those other tabs in the Remote Destkop dialog are for!

Mapping local drives to a Remote Desktop connection.

This is a handy tip to go with these others:

Art of the Job Post

Mona Lisa When I was a bright eyed bushy tailed senior in college, I remember wading through pages and pages of job ads in Jobtrak (which has since been absorbed into Monster.com).

Most of the ads held my attention in the same way reading a phone book does. The bulk of them had something like the following format.

Responsibilites:

Design and develop data-driven internet based applications that meet functional and technical specifications. Use [technology X] and [technology Y] following the [methodology du jour] set of best practices. Create documentation, review code, and perform testing.

Required Skills and Experience:

Must have X years in language [now outdated language]. Must be proficient in BLAH, BLAH, and BLAH. Ability to work in a team environment. Able to work in a fast-paced [meaning we’ll work your ass off] environment.

I know what you’re thinking. Where do I sign up!

Yaaaaawn. Keep in mind, this was in 1997 just as the job market was starting to reach the stratosphere. Competition was tight back then. Do a search on Dice.com right now and you’ll still see a lot of the same.

I’m sorry, but your job posting is not the place to spew forth a list of Must have this and Must have that and a list of responsibilities so plain and vanilla that...that... I just don’t have a good analogy for it. Sorry.

These type of ads are attempting to filter out candidates who do not meet some laundry list of requirements. But this is not the goal of a good job ad. A good job ad should not explain what hoops the candidate must jump through to join your company, it should explain why the candidate should even want to jump through those hoops in the first place.

This of course assumes you are attempting to hire some star developers away from their current jobs rather than resume padders who have spent most of their careers in training classes so they can place your laundry list of technology TLAs underneath their name on their resume.

Certainly, a job posting should explain briefly the type of work and experience desired to fill the role. No point in having a person who only has experience in sales and marketing applying for your senior DBA position (true story). But first and foremost, you want to catch the attention of a great candidate. Boring job ads that read like the one above do not capture the imagination of good developers.

Back to my story. As I said, most of the ads fit this mold, but there were a few here and there that popped off the screen. I wish I had saved the one that really caught my attention. It was from a small company named Sequoia Softworks (which is still around but now named Solien) My memory of it is vague, so I’ll just make something up that resembles the spirit of the ad. All I remember is that it started off by asking questions.

Are you a fast learner and good problem solver? Are you interested in solving interesting business problems using the latest web technologies and building dynamic data driven web applications?

We’re a small web development company in Seal Beach (right by the beach in fact!) looking for bright developers. We have a fun casual environment (we sometimes wear shorts to work) with some seriously interesting software projects.

Experience in Perl, VBScript, and SQL is helpful, but being a quick learner is even more important. If you’ve got what it takes, give us a call.

I ended up working there for six years, moving up the ranks to end up as the Manager of Software Development (never once writing a line of PERL). They did several things right in their ad, as I recall.

Challenge the reader and demand an answer!

Do you have two years experience in C#? is not a challenge to the reader. This is not a question that captures my attention nor draws me in demanding an answer.

Do you know C# like Paris Hilton knows manafacturing fame? Now that is a challenge to my intellect! Hell yeah I know C# like nobody’s business. That kind of question demands an answer.  And a good candidate is more likely to drive over to your headquarters and give it to you.

Appeal to vanity

Not every appeal to vanity is a bad thing. It doesn’t always amount to sucking up. This point is closely related to the last point in that an appeal to vanity is also a challenge to a candidate to show just how great they are. Asking someone if they are a good problem solver, for example, conjures up a desire to prove it.

Show some personality

Sure, many corporations seem like soulless cubicle farms in which workers are seen as mindless drones. But surely not your company, right? So why does your job posting have a tombstone all over it?

Who wants to be another cog in a machine performing mundane tasks for god knows what reason? Your ad should express a bit of your company’s personality and culture.  It should also indicate to the reader that people who come to work for you are going to work with people. Interesting people. And they are going to work on interesting projects.

I write all this because of an article I read about business schools. It was a throw-away quote in which some employer mentioned how his new employee fresh out of business school helped rewrite some job postings and they were able to quickly fill some positions with high quality candidates they had been struggling to fill.

A well written job posting makes a difference.

I mentioned before that I am participating in the HiddenNetwork job board network because I really believe in the power of blogs to connect good people with good jobs. It’s in its nascent stages so I really don’t know how well it is fulfilling that mission yet, but I believe that it will do well.

If you do post a job via my blog (yes, I get a little something something if you do), be sure to make it a good posting that really captures the imagination of good developers (as all my readers are!  See. Appeal to vanity.). It’s even more of a challenge given how few words you have at your disposal for these ads.

The Misuse of the Space Shuttle Analogy

Space Shuttle Landing Jeff Atwood writes a great post about The Last Responsible Moment. Take a second to read it and come back here. I’ll wait.

In the comments, someone named Steve makes this comment:

This is madness. Today’s minds have been overly affected by short attention span music videos, video games, film edits that skip around every .4 seconds, etc.

People are no longer able to focus and hold a thought, hence their "requirements" never settle down, hence "agile development", extreme coding, etc.

I wonder what methodology the space shuttle folks use.

You shouldn’t humor this stuff, it’s a serious disease.

Ahhhh yes. The Space Shuttle. The paragon of software development. Nevermind the fact that 99.999% of developers are not developing software for the Space Shuttle, we should all write code like the Shuttle developers. Let’s delve into that idea a bit, shall we?

Invoking the Space Shuttle is common when arguing against iterative or agile methodologies to building software. Do people really think hey, if agile wont work for the Space Shuttle, how the hell is it going to work for my clients widget tracking application? Gee, your widget app is doomed.

The Space Shuttle is a different beast entirely from what most developers deal with day in and day out. This is not to say that there aren’t lessons to be learned from how the Shuttle software is built, there certainly are. Good lessons. No, great lessons! But in order to make good use of the lessons, you must understand how your client is very different from the client to the Shuttle developers.

One reason that the requirements for the Space Shuttle can be more formally specified beforehand and up front is because the requirements have very little need to chang once the project is underway. When was the last time the laws of gravity changed? The Shuttle code is mostly an autonomous system, which means the “users” of the code is the Shuttle itself as well as the various electronic and mechanical systems that it must coordinate.  These are well specified systems that do not need to change often, if at all, in the course of a project.

Contrast this to business processes which are constantly evolving and heavily people centric. Many times, the users of a system aren’t even sure about how to solve the business problem they are trying to solve with software.  This is partly why they don’t exactly know what they want until they have the solution in hand. We can wave activity diagrams, list of requirements, user stories and use cases in front of them all day long, but these are rough approximations of what the final system will do and look like. It’s showing the user a pencil sketch of a stick figure and hoping they see the Mona Lisa.

Later in the comments, the same guy Steve responds with what we should do with users to focuse them.

1) what do you want it to do?
2) understand the business as much as you can
3) draw a line in the sand for that which you can safely deliver pretty soon
4) build a system that is extensible, something that can be added on too fairly easily, because changes are coming (that is agile-ness)
5) charge for changes

And I agree. One of the common misperceptions of agile approaches is that you never draw a line in the sand. This is flat out wrong. You do draw a line in the sand, but you do it every iteration.

Unlike the BDUF Waterfall approach which requires that you force the user to spew requirements until he or she is blue in the face, with iterative approaches you gather a list of requirements and prioritize them according to iterations.  This helps a long way to avoiding poor requirements due to design fatique. The user can change any requirements for later iterations, but once an iteration has commenced, the line in the sand is drawn for that iteration.

To me, this sounds like the last responsible moment for deciding on a set of requirements to implement. You don’t have to decide on the entire system at the beginning. You get some leeway to trade requirements for later iterations. You only are forced to decide for the current iteration.

 

Atlas Web Application Project Template

Dave (a Subtext developer) just blogged about a project template he created for creating Atlas applications using the Web Application Project (WAP).  This is wicked useful for those of us who prefer Web Application Projects over Web Site Projects.

Atlas Web App Proj
Tags: ,

OriginUrl Supports Regular Expressions

In a recent post I ranted about how ASP.NET denies WebPermission in Medium Trust. I also mentioned that there may be some legitimate reasons to deny this permission based on this hosting guide.

Then Cathal (thanks!) emailed me and pointed out that the originUrl does not take wildcards, it takes a regular expression.

So I updated the <trust /> element of web.config like so:

<trust level="Medium" originUrl=".*" />

Lo and Behold, it works! Akismet works. Trackbacks work. All in Medium Trust.

Of course, a hosting provider can easily override this as Scott Guthrie points out in my comments. I need to stop blogging while sleep deprived. I have a tendency to say stupid things.

Now a smart hosting company can probably create a custom medium trust policy in order to make sure this doesn’t work, but as far as I can tell, this completely works around the whole idea of denying WebPermission in Medium Trust.

If I can simply add a regular expression to allow all web requests, what’s the point of denying WebPermission?

Interesting Perf Lesson

Tyler, an old friend and an outstanding contractor for VelocIT recently wrote a post suggesting one would receive better performance by passing in an array of objects to the Microsoft Data Application Block methods rather than passing in an array of SqlParameter instances. He cited this article.

The article suggests that instead of this:

public void GetWithSqlParams(SystemUser aUser)
{
  SqlParameter[] parameters = new SqlParameter[]
  {
    new SqlParameter("@id", aUser.Id)
    , new SqlParameter("@name", aUser.Name)
    , new SqlParameter("@name", aUser.Email)
    , new SqlParameter("@name", aUser.LastLogin)
    , new SqlParameter("@name", aUser.LastLogOut)
  };

  SqlHelper.ExecuteNonQuery(Settings.ConnectionString
    , CommandType.StoredProcedure
    , "User_Update"
    , parameters);
}

You should do something like this for performance reasons:

public void GetWithSqlParams(SystemUser aUser)
{
  SqlHelper.ExecuteNonQuery(Settings.ConnectionString
    , CommandType.StoredProcedure
    , "User_Update"
    , aUser.Id
    , aUser.Name
    , aUser.Email
    , aUser.LastLogin
    , aUser.LastLogout);
}

Naturally, when given such advice, I fall back to the first rule of good performance from the perf guru himself, Rico Mariani. Rule #1 Is to Measure. So I mentioned to Tyler that I’d love to see metrics on both approaches. He posted the result on his blog.

Calling the methods included in a previous post, 5000 times each,

With parameters took 1203.125 milliseconds.
With objects took 1250 milliseconds. 
Objects took -46.875 milliseconds less.

20000 times each:

With parameters took 4859.375 milliseconds.  
With objects took 5015.625 milliseconds.
Objects took -156.25 milliseconds less.

The results show that the performance difference is negligible. However, even before seeing the performance results, I would agree with the article to choose the second approach, but for different reasons. It results in a lot less code. As I have said before, Less code is better code.

I tend to prefer optimizing for productivity all the time, but only optimizing for performance after carefully measuring for bottlenecks.

There’s also a basic economics question hidden in this story. The first approach does seem to eke out slightly better performance, but at what cost? That’s a lot more code to write to eke out 47 milliseconds worth of performance out of 5000 method calls. Is it really worth it?

This particular example may not be the best example of this principle of wasting time optimizing at the expense of productivity because there is one redeeming factor worth mentioning with the first approach.

By explicitly specifying the parameters, the parameters can be listed in any order, whereas the second approach requires that the parameters be listed in the same order that they are specified in the stored procedure. Based on that, some may find the first approach preferable. Me, I prefer the second approach because it is cleaner, easier to read, and I don’t see keeping the order intact much more work than getting the parameter names correct.

But that’s just me.

Why Oh Why Couldn't WebPermission Be Part Of Medium Trust?

Source: http://macibolt.hu/pag/goldilock.htmlThis is a bit of rant born out of some frustrations I have with ASP.NET. When setting the trust level of an ASP.NET site, you have the following options:

Full, High, Medium, Low, Minimal

It turns out that many web hosting companies have chosen to congregate around Medium trust as a sweet spot in terms of tightened security while still allowing decent functionality. Only natural as it is the one in the middle.

For the most part, I am sure there are very good reasons for which permissions make it into Medium trust and which ones are not allowed. But some decisions seem rather arbitrary. For example, WebPermission. Why couldn’t that be a part of the default Medium trust configuration? I mean really? Why not? (Ok, there are really good reasons, but remember, this is a rant, not careful analysis. Bear with me. Let me get it off my chest.)

Web applications have very good reason to make web requests (ever hear of something called a web service. They may take off someday) and how damaging is that going to be to a hosting environment. I mean, put a throttle on it if you are that concerned, but don’t rule it out entirely!

I really do want to be a good ASP.NET citizen and support Medium Trust with applications such as Subtext, but what a huge pain it is when some of the best features do not work under Medium Trust. For example, Akismet.

Akismet makes a web request in order to check incoming comments for spam. I tried messing around with wildcards for the originUrl attribute of the <trust /> element, but they don’t work. In fact, I only found a single blog post that said it would work, but no documentation that backed that claim up.

Instead, you need access to the machine.config file (as the previously linked blog post describes), which no self respecting host is going to just give you willy nilly. Nope. In order to get Akismet to work under medium trust, I have to tell Subtext users that they must beg, canoodle, and plead with their host provider to update the machine.config file to allow unrestricted access to the WebPermission. Good luck with that.

If they don’t give unrestricted access, then they need to add an originURl entry for each URL you wish to request. Hopefully machine.config entries do allow wildcards because the URL for an Akismet request includes the Akismet API code. Otherwise running an Akismet enabled multiple user blog in a custom Medium Trust environment would be a royal pain.

Hopefully you can see the reason behind all my bitching and moaning. A major goal for Subtext is to provide a really simple and easy installation experience. At least as easy as possible for installing a web application.  Having an installation step that requires groveling does not make for a good user experience.  But then again, security and usability have always created tension between them.

Scott Watermasysk points out a great guide to enabling WebPermission in Medium Trust for hosters. So if you’re going to be groveling, at least you have a helpful guide to give them. The guide also points out the security risks in involved with Medium Trust.

Related Posts:

Metrics For Your Open Source Project

Steve Harman finds this gem of a site that generates interesting statistics and graphs for an open source website.  Just point it to your code repository and let it go!

Some stats

Check out the Subtext project stats.

Remote Desktop On A Non-Standard Port

For a project I’m working on, we have an automated build server running CruiseControl.NET hosted in a virtual machine.  We do the same thing for Subtext

Some of you may have multiple virtual servers running on the same machine.  Typically in such a setup (at least typically for me), each virtual server won’t have its own public IP Address, instead sharing the public IP of the host computer.

This makes it a tad bit difficult to manage the virtual servers since using Remote Desktop to connect to the public IP will connect to the host computer and not the virtual machine.  The same thing applies to multiple real computers behind a firewall.

One solution (and the one I use) is set up each virtual server to run Terminal Services, but each one listens on a different port.  Then set up port-forwarding on your firewall to forward requests for the respective ports to the correct virtual machine.

Configuring the Server

The setting for the Terminal Services port lives in the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TerminalServer\WinStations\RDP-Tcp

Open up Regedit, find this key, and look for the the PortNumber value.

PortNumber Setting

Double click on the PortNumber setting and enter in the port number you wish to use. Unless you think in hex (pat yourself on the back if you do), you might want to click on decimal before entering your new port number.

Port Number Value Dialog

Or, you can use my creatively named VelocIT Terminal Services Port Changer application, which is available with source.  This is a simple five minute application that does one thing and one thing only. It allows you to change the port number that Terminal Services listens on.

VelocIT Terminal Services Port Changer

Remember, all the usual caveats apply about tinkering with the registry. You do so at your own risk.

Connecting via Remote Desktop to the non-standard Port

Now that you have the server all set up, you need to connect to it.  This is pretty easy.  Suppose you change the port for the virtual machine to listen in on port 3900.  You simply append 3900 to the server name (or IP) when connecting via Remote Desktop.

Remote Desktop

Keep In Mind

Keep in mind that the user you attempt to connect with must have the logon interactively right as well as permissions to logon to the terminal services session.  For more on that, check out this extremely helpful article with its trouble shooting section.

That’s pretty easy, no?  Now you should have no problem managing your legions of virtual servers.

Related Posts:

Dogfooding My Blog

Just upgraded my blog to the latest version of Subtext in the Subversion 1.9 branch, not that you needed to know that. I just appreciate you letting me know if you run into problems leaving a comment and such by using my Contact page.

Before I release 1.9.2 (long story why that's ends with a 2 and not 1), I need to update the Contact page so that spam filters also apply to the contact page.

Tags:

Can't Sleep, Feeling Sick, So I Code

Weird how coding on Subtext relaxes me. For the past couple days I’ve been feeling a bit under the weather and getting worse.  The weird part is that anytime I try and eat something, there’s a terrible after-taste. And no, it’s not my breathe.  I couldn’t finish my pizza tonight.  Pizza!

Anyways, I couldn’t sleep tonight so I figured hacking on some Subtext code might relax me.  I fixed some bugs and implemented FeedBurner support in Subtext, using the DasBlog code as a guide, though the way we implement feeds is much different.  It’ll come out in the next edition of Subtext.

Unfortunately, it may take me longer to release because although coding on Subtext feels good when I’m sick, QA testing doesn’t.

A Gotcha Identifying the User's IP Address

Recently I wrote a .NET based Akismet API component for Subtext.  In attempting to make as clean as interface as possible, I made the the type of the property to store the commenter’s IP address of type IPAddress.

This sort of falls in line with the Framework Design Guidelines, which mention using the Uri class in your public interface rather than a string to represent an URL.  I figured this advice equally applied to IP Addresses as well.

To obtain the user’s IP Address, I simply used the UserHostAddress property of the HttpRequest object like so.

HttpContext.Current.Request.UserHostAddress

The UserHostAddress property is simply a wrapper around the REMOTE_ADDR server variable which can be accessed like so.

HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]

For users behind a proxy (or router), this returns only one IP Address, the IP Address of the proxy (or router).  After some more digging, I learned that many large proxy servers will append their IP Address to a list maintained within another HTTP Header, HTTP_X_FORWARDED_FOR or HTTP_FORWARDED.

For example, if you make a request from a country outside of the U.S., your proxy server might add the header HTTP_X_FORWARDED_FOR and put in your real IP and append its own IP Address to the end. If your request then goes through yet another proxy server, it may append its IP Address to the end.  Note that not all proxy servers follow this convention, the notable exception being anonymizing proxies.

Thus to get the real IP address for the user, it makes sense to check the value of this first:

HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]

If that value is empty or null, then check the UserHostAddress property.

So what does this mean for my Akismet implementation?  I could simply change that property to be a string and return the entire list of IP addresses.  That’s probably the best choice, but I am not sure whether or not Akismet accepts multiple IPs.  Not only that, I’m really tired and lazy, and this change would require that I change the Subtext schema since we store the commenter’s IP in a field just large enough to hold a single IP address.

So unless smart slap me upside the head and call me crazy for this approach, I plan to look at the HTTP_X_FORWARDED_FOR header first and take the first IP address in the list if there are any.  Otherwise I will grab the value of UserHostAddress.  As far as I am concerned, it’s really not that important that I am 100% accurate in identifying the remote IP, I just need something consistent to pass to Akismet.

Tip For Managing Remote VMWare Server

Quick tip for you if you need to remotely connect to a server with VMWare Server installed in order to manage the virtual server. 

VMWare Server Console doesn’t work correctly if you Remote Desktop or Terminal in. You have to physically be at the machine or Remote Desktop into the Console session.

The symptoms I ran into was that I could not open a virtual machine, and when I tried to create a new one, I got an “Invalid Handle” error.

Technorati Tags:

Structuring Unit Test Code

Jeremy Miller asks the question, “How do you organize your NUnit test code?”.  My answer? I don’t, I organize my MbUnit test code.

Bad jokes aside, I do understand that his question is more focused on the structure of unit testing code and not the structure of any particular unit testing framework.

I pretty much follow the same structure that Jeremy does in that I have a test fixture per class (sometimes more than one per class for special cases).  I experimented with having a test fixture per method, but gave up on that as it became a maintenance headache.  Too many files!

One convention I use is to prefix my unit test projects with "UnitTest".  Thus the unit tests for Subtext are in the project UnitTests.Subtext.dll.  The main reason for this, besides the obvious fact that it’s a sensible name for a project that contains unit tests, is that for most projects, the unit test assembly would show up on bottom in the Solution Explorer because of alphabetic ordering.

So then I co-found a company whose name starts with the letter V.  Doh!

UPDATE: I neglected to point out (as David Hayden did) that with VS.NET 2005 I can use Solution Folders to group tests. We actually use Solution Folders within Subtext. Unfortunately, many of my company work is still using VS.NET 2003, which does not boast such a nice feature.

One thing I don’t do is separate my unit tests and integration tests into two separate assemblies.  Currently I don’t separate those tests at all, though I have plans to start. 

Even when I do start separating tests, one issue with having unit tests in two separate assemblies is that I don’t know how to produce NCover reports that merge the results of coverage from two separate assemblies.

One solution I proposed in the comments to Jeremy’s post is to use a single assembly for tests, but have UnitTests and Integration Tests live in two separate top level namespaces.  Thus in MbUnit or in TD.NET, you can simply run the tests for one namespace or another.

Example Namespaces: Tests.Unit and Tests.Integration

In the root of a unit test project, I tend to have a few helper classes such as UnitTestHelper, which contains static methods useful for unit tests. I also have a ReflectionHelper class, just in case I need to “cheat” a little. Any other classes I might find useful typically go in the root, such as my SimulatedHttpRequest class as well.

Software Development Is A Religion

Jeff Atwood writes a great rebuttal to Steve Yegge’s rant on Agile methodologies.  I won’t expound on it too much except to point out this quote which should be an instant classic, emphasis mine:

Steve talks about “staying lightweight” as if it’s the easiest thing in the world, like it’s some natural state of grace that developers and organizations are born into. Telling developers they should stay lightweight is akin to telling depressed people they should cheer up.

Heh heh.  Jeff moves from a Coding Horror to a Coding Hero.

Now while I agree much of it is religion, I like to think that the goal is to remove as much religion out of software development as possible.  A key step, as Jeff points out, is recognizing which aspects are religion.

...the only truly dangerous people are the religious nuts who don’t realize they are religious nuts.

It’s like alcoholism.  You have to first accept you are an alcoholic.  But then, once recognizing that, you strive to make changes.

For example, Java vs .NET is a religious issue insofar as one attempts to make an absolute claim that one is superior to the other. 

However it is less a religious issue to say that I prefer .NET over Java for reasons X, Y, and Z based on my experience with both, or even to say that in situation X, Java is a preferred solution.

Likewise, just because double-blind tests are nearly impossible to conduct does not mean that we cannot increase the body of knowledge of software engineering. 

For the most part, we turn to the techniques of social scientists and economists by poring over historical data and looking at trends to extrapolate what information we can, with appropriate margins of error. 

Thus we can state, with a fair degree of certainty, that:

Design is a complex, iterative process. Initial design solutions are usually wrong and certainly not optimal.

That is fact 28 of Facts and Fallacies of Software Engineering by Robert L. Glass, who is by no means an agile zealot.  Yet this fact does show a weakness in waterfall methodologies that is addressed by agile methodologies, a differentiation that owes more to the scientific method than pure religion.

Tivo For Your Registry

Tivo Icon Ever prolific Jon Galloway has released another tool on our tools site.  When we started the tools site, I talked some trash to spur some friendly competition between the two of us.  Let’s just say Jon is kicking my arse so hard my relatives in Korea can’t sit down.

His latest RegmonToRegfile tool works with yet another SysInternals tool, Regmon.

Winternals (maker of Sysinternal) released many fantastic tools for managing and spelunking your system.

So great, in fact, that Robb feels he owes them his child in gratitude.

Kudos to Microsoft for snatching up Mark Russinovich and Winternals Software.

Regmon is essentially a Tivo for your registry, allowing you to record and play back changes to the registry.

Regmon lacks the ability to export to a registry (.reg) file, which is where Jon’s tool comes to play.  It can parse the Regmon log files and translate them to .reg files.

Here is a link to Jon’s blog post on this tool.

 

Comment Spam Relief In Subtext Coming Soon

Personal matters (good stuff) and work has been keeping me really busy lately, but every free moment I get I plod along, coding a bit here and there, getting Subtext 1.9.1 “Shields Up” ready for action.

There were a couple of innovations I wanted to include in this version as well as a TimeZone handling fix, but recent comment spam shit storms have created a sense of urgency to get what I have done out the door ASAP.

In retrospect, as soon as I finished the Akismet support, I should have released.

I have a working build that I am going to test on my own site tonight.  If it works out fine, I will deploy a beta to SourceForge.  This will be the first Subtext release that we label Beta.  I think it will be just as stable as any other release, but there's a significant schema change involved and I want to test it more before I announce a full release.

Please note, there is a significant schema change in which data gets moved around, so backup your database and all applicable warnings apply.  Upgrade at your own risk.  I am going to copy my database over and upgrade offline to test it out before deploying.

Shields up edition will contain Akismet support and CAPTCHA.  The Akismet support required adding comment “folders” to allow the user to report false positives and false negatives.

Power Tools For Disk Defragmenting

Disk Defragmenter

For the most part, the Disk Defragmenter application (located at %SystemRoot%\system32\dfrg.msc) that comes with Windows XP does a decent enough job of defragmenting a hard drive for most users.

But if you’re a developer, you are not like most users, often dealing with very large files and installing and uninstalling applications like there’s no tomorrow.  For you, there are a couple of other free utilities you should have in your utility belt.

Recently I noticed my hard drive grinding a lot.  After defragmenting my drive, I clicked on the View Report button this time (I normally never do this out of hurriedness).

Disk Defrag Dialog

This brings up a little report dialog.

Defrag Report

And in the bottom, there is a list of files that Disk Defragmenter could not defragment.  In this case, I think the file was simply too large for the poor utility.  So I reached into my utility belt and whipped out Contig.

Contig

Contig is a command line utility from SysInternals that can report on the fragmentation of individual files and defrag an individual file.

I opened up a console window, changed directory to the Backup directory, and ran the command:

contig *.tib

Which defragmented every file ending with the tib extension (in this case just one).  This took a good while to complete working against a 29 Gig file, but successfully reduced the fragmens from four to two, which made a huge difference.  I may try again to see if it can bring it down to a single fragment. 

I ran Disk Defragmenter again and here are the results.

Disk Defragmenter

Keep in mind that the disk usage before this pass with the defragger was the usage after running Disk Defragmenter once.  After using contig and then defragging again, I received much better results.

PageDefrag

Another limitation of Disk Defragmenter is that it cannot defragment files open for exclusive access, such as the Page File.  Again, reaching into my utility belt I pull yet another tool from Sysinternals (those guys rock!), PageDefrag.

Running PageDefrag brings up a list of page files, event log files, registry files along with how many clusters and fragments make up those files.

Page Defrag

This utility allows you to specify which files to defrag and either defragment them on the next reboot, or have them defragmented at every boot.  As you can see in the screenshot, t