0 comments suggest edit

Dr. Evil It’s an odd quirk of our taste for “round” numbers that we tend to celebrate milestones that are multiples of a power of ten. For example, a 10th anniversary is somehow more significant than a 6th anniversary. Likewise, a 100th post is more significant than a 73rd post.

Kim Il Jong This post reaches a different sort of milestone, it is my 666th post. Yes, this post bears with it the mark of the beast. I dedicate this post to pure eeeeevil.

Evil Calvin Not having a reputation evil, my first step is to gauge my current evil quotient via the “How evil are you?” website. Unfortunately I rated quite good on the Evil-o-meter. There was certainly work to do.

So chomped down on my Cuban cigar, fired up Internet Explorer (evil-o-meter rising) and navigated to the evil overload list. Using Powerpoint (+2 on the evil-o-meter) I copied the list verbatim (DMCA anyone?) and started committing them to memory.

After getting a bit bored, I spent a little time doing some stem cell research and even tried my hand at human cloning. I thought about having an abortion, but as I am male, had a tough time getting pregnant. So I changed tactics and bought an H2 and drove it into a nature preserve while smoking an illegal substance and drinking a forty.

At this point, I realized that to really get the evil-o-meter soaring, I should SPAM people. Not only should I create SPAM, I should write a web service to do so. I wrote one that returned an ADO.NET DataSet of email addresses and websites with comments enabled so that others could join in the SPAMination. Soon all the world would know about all the latest Texas Hold-Em websites.

Oh, did I mention that application is written with only one line of code? And there are no comments. And I used HTML Tables and NO CSS. It’s covered in Hungarian Notation. And I have promoted it as an example of “SOA”. And the application connects to the (non-normalized) database using the SA account without a password. I used inline sql without using parameterized queries. Yes, Satan himself is starting to get worried here. But then again, I personally didn’t write this code, I off-shored it to a sweatshop in China that employs overworked six year olds to hack out the code.

Evil Bert After all this hard work, I relaxed to a game of Dungeons & Dragons while watching a little sesame street to absorb the evil that is Bert. This led to an internal debate about which character is more evil, Barney or Bert?

Evil Barney After studying this mathematical proof of Barney’s evil and this essay, “Why is Barney Considered Evil”, I concluded that indeed, Barney is more evil.

I considered creating a Marketing website without an RSS feed, but not even I was ready to go that far.

After all that, I went back to retake the evil survey. It turns out that I may have done a bit too much research as the site declared that I wasn’t evil but clinically insane. Not bad for a day’s work. I wonder what post should I dedicate to insanity?

[Listening to: Thriller - Michael Jackson - HIStory, Past, Present And Future, Book 1 (Compilation) (Disc 1) (5:57)]

sql 0 comments suggest edit

I’m not sure if this is common knowledge, but you can place template parameters in your SQL scripts and evaluate them within query analyzer. I think I learned this one a long time ago from a former fantastic SysAdmin, turned DBA, turned Developer, Tyler.

Here’s an example of a short script that makes use of a template variable.

`SELECT * FROM <tableName, varchar(32), 'MyTable'>`

Paste that into SQL Query Analyzer and hit CTRL+SHIFT+M. A dialog to replace the template parameters will pop up like so

Replace Template Parameters
Dialog

Just fill in the values and hit return and you’re ready to run the script.

The format for a template parameter is <parameterName, sql data type, default value>.

0 comments suggest edit

In a previous post I mentioned a problem I was having with implementing RFC3229. Well I got that one fixed, but realized that I had another very subtle bug. One that is potentially encouraged by the examples in the spec.

Before I begin, please realize that the examples are not an implementation specification. They are simply examples of how one might implement this RFC. Having said that, many implementors will probably conform to the examples as I did.

At issue is that all the examples show an integer entity tag value. Presumably this would be the id of the feed item (or post) within your backend database. In Subtext, this value maps to an integer primary key field that is an auto-incrementing identity.

So suppose you have a blog an a reader with an RFC3229-compliant aggregator makes a request for your feed. It might look like

GET /Rss.aspx HTTP/1.1Host: haacked.comIf-None-Match: "100"A-IM: feed, gzip

The “100” represents the last feed item that the aggregator making the request saw. The server presumably does a lookup to return all feed items with an ID that is greater than this number, creates a feed with those items, and sends that to the client. Bandwidth is saved as the entire feed doesn’t need to be sent, just the items with an id greater than 100.

Now suppose you had posted five items since the aggregator last made a request. The response header might look like:

HTTP/1.1 226 IM UsedETag: "105"IM: feed, gzipDate: Thu, 30 Jun 2005 23:48:05 GMTCache-Control: no-store, im

Your server is telling the aggregator client, “Hey! The last item you are getting has an e-tag of 105. Make sure to send the value 105 in your next request.”

Well at least that’s how I implemented it in Subtext. The problem is that this implementation has a very subtle bug. Can you see the problem?

Since the table that stores blog entries has its id field as an identity, I am assured that a newer element has a higher id than an older element, so that’s not necessarily the problem. The problem is that Subtext (and I presume other blogging engines) allows the author to create a post that is not published.

So suppose a blogger create a post with an ID of 106 that isn’t published. This same blogger then creates and publishes a post with an ID of 107. The next request for the feed will get just item 107 and the server response will look like

HTTP/1.1 226 IM UsedETag: "107"IM: feed, gzipDate: Fri, 01 Jul 2005 01:15:03 GMTCache-Control: no-store, im

Now say that the blogger fixes up the oh so important post 106 and finally publishes it. The next request for the feed from that aggregator will look like

GET /Rss.aspx HTTP/1.1Host: haacked.comIf-None-Match: "107"A-IM: feed, gzip

Your server will send the aggregator all feed items with an id greater than 107, completely skipping the newly published item 106. This poor aggregator completely misses out on the beauty and sublime writing that was surely within post 106.

In order to rectify this situation, I need to add a DatePublished field to my database table and use that to as the entity tag and to determine which items an aggregator has and hasn’t seen. That will ensure that important posts aren’t ignored from RFC3229 compliant aggregators.

0 comments suggest edit

Jaw Fragment From the title of his post, Dream Hangovers, I thought Robb was going to tell some story about another night of too much drinking and the painful consequences afterwards. Instead he talks about how realistic dreams can often influence your mood the following day.

A few nights ago I had a dream in which I kept biting down on something hard. I spat the foreign object into my hand and was surprised to find a molar. For some reason, losing my teeth is a typical nightmare for me when I’m anxious. However this time, it was much more intense than before.

After spitting out a few teeth, I noticed I was biting on something much larger that felt like a rock or a piece of plaster. I spit it out and it my hand was a gleaming pale chunk of my jaw. Another chunk came out and I rushed to the bathroom to look in the mirror. When I opened my mouth, my entire lower jaw caved in and blood started filled up my mouth and pouring into the sink along with white pieces of my jaw. It reminded me of a river full of floating icebergs. That’s when I woke up in a cold sweat breathing very hard, furtively checking all my teeth with my tongue.

After a few moments of abject terror, I calmed down and thanked my lucky stars that all my teeth were there.

0 comments suggest edit

You kind of get the feeling that Keith Brown has a beef with soap exceptions when he writes that SoapException Sucks. I won’t rehash everything he says here, but the gist of his complaint is that when throwing an exception from within a web service, the exception gets wrapped by a SoapException. What’s so bad about that? As Keith relates, the Message property of the SoapException class intersperses your fault string with a load of other crap you really don’t care about. Also, the InnerException doesn’t get serialized into the SOAP fault packet, so it is always null on the client side.

A couple solutions proposed within his comments require putting a try/catch around the body of every method and construct a suitable SoapException by hand. This just didn’t sit well with me (neither did the burrito I just ate) as it seemed quite repetitive. I figured there had to be a better way. If only there were some way to inject code after a SOAP method is called and before the XML payload is delivered to the client. Fortunately there is. SOAP Extensions!

The solution I hacked together here is to build a custom SoapExtensionAttribute used to mark up a method. If that method throws an exception, the original exception information is serialized into the detail element of the soap exception.

The key here is to remember that SOAP is at its core simply XML text messages being sent back and forth between computers. A SoapExtension lets you peek under the hood and manipulate the actual messages going in and out.

There are three classes involved in this solution, SerializedExceptionExtensionAttribute, SerializedExceptionExtension and SoapOriginalException. I’ll briefly go over each one.

SerializedExceptionExtensionAttribute is a very simple Attribute class that inherits from SoapExtensionAttribute. When applied to a target, this attribute has a property that indicates what type of SoapExtension to use for that target.

SerializedExceptionExtension inherits from SoapExtension and for the most part looks like your typical MSDN example of a soap extension in which you override ChainStream, store the old stream in a member variable, and replace it with a new stream. For the sake of illustration, I will highlight a few methods that make this extension somewhat interesting (at least for me)…

public override void ProcessMessage(SoapMessage message)
{
    if(message.Stage == SoapMessageStage.AfterSerialize)
    {
        _newStream.Position = 0;
        if(message.Exception != null && message.Exception.InnerException != null)
        {
            InsertDetailIntoOldStream(message.Exception.InnerException);
        }
        else
        {
            CopyStream(_newStream, _oldStream);   
        }
    }
    else if(message.Stage == SoapMessageStage.BeforeDeserialize)
    {
        CopyStream(_oldStream, _newStream);
        _newStream.Position = 0;
    }
}

void InsertDetailIntoOldStream(Exception exception)
{
    XmlDocument doc = new XmlDocument();
    doc.Load(_newStream);
    XmlNode detailNode = doc.SelectSingleNode("//detail");

    try
    {
        detailNode.InnerXml = GetXmlExceptionInformation(exception);
    }
    catch(Exception exc)
    {
        detailNode.InnerXml = exc.Message;
    }

    XmlWriter writer = new XmlTextWriter(_oldStream, Encoding.UTF8);
    doc.WriteTo(writer);
    writer.Flush();
}

In the method ProcessMessage, you can see that the code waits till after the method has been serialized to XML (represented by SoapMessageStage.AfterSerialize) and is ready to be sent back to the client. That’s where the exception detail is injected into the stream, assuming an exception did occur.

InsertDetailIntoOldStream finds the detail node within the serialized stream and inserts exception information into that node. In order to make this information useful to both non .NET clients and .NET clients, the exception information is formatted as XML. However, in one of the nodes of that XML, I serialize the exception using a BinaryFormatter. That way, a .NET client can gain access to the full original exception.

string GetXmlExceptionInformation(Exception exception)
{
    string format = "<Message>{0}</Message>"
        + "<Type>{1}</Type>"
        + "<StackTrace>{2}</StackTrace>"
        + "<Serialized>{3}</Serialized>";
    return string.Format(
        format,
        exception.Message,
        exception.GetType().FullName,
        exception.StackTrace,
        SerializeException(exception));
}

string SerializeException(Exception exception)
{
    MemoryStream stream = new MemoryStream();
    IFormatter formatter = new  BinaryFormatter();
    formatter.Serialize(stream, exception);
    stream.Position = 0;
    return Convert.ToBase64String(stream.ToArray());
}

Security Note!, for a production system, you probably don’t want to serialize the original exception as it will contain a stack trace and could give out more information than you wish clients to the service to have. For debugging, however, this is quite useful.

Allow me to walk through how you can apply these classes in your own code. Below, I’ve written a method that simply throws an exception. You can see that I marked it with the SerializedExceptionExtension attribute.

[WebMethod, SerializedExceptionExtension]
public string ThrowNormalException()
{
    throw new ArgumentNullException("MyParameter", "Exception thrown for testing purposes");
}

Now on the client, I simply make a call to the web service within a try/catch clause. In the snippet below, you’ll notice that I wrap the thrown exception with the SoapOriginalException class. That class is a helpful wrapper that knows how to deserialize an exception serialized using this technique. The original exception is accessed via the InnerException property.

void CallService()
{
    TestService proxy = new TestService();
    try
    {
        proxy.ThrowNormalException();
    }
    catch(SoapException e)
    {
        SoapOriginalException realException = new SoapOriginalException(e);
        Console.WriteLine(realException.InnerException.Message);
    }
}

If you’d like to try this technique out yourself and provide a critique, download the ExceptionInjectionWithSoapExtension.zip source files here. There are certainly some enhancements that could be made to the code to make it even more useful. Let me know if you make improvements.

0 comments suggest edit

Real Madrid Wohoo! The little lady and myself will be in attendance as we watch Zinedine Zidane, Beckham, Ronaldo, Owen, Roberto Carlos and the rest of Real Madrid completely overpower and dismantle the lackluster Galaxy when they play an exhibition game at the Home Depot Center in Carson.

It’ll be interesting to see if Landon Donovan can scrape together a worthy performance in the face of such talent and show that he’s ready for the world stage.

I remember when living in Madrid, Spain just how revered Real Madrid is. They are a storied team with a rich history and a fantastic roster this year. Of course, too much star power can sometimes be a detriment, as we learned with the lakers last year, and as we saw this year as second place Real Madrid were upstaged by Barcelona for the Spanish League title.

0 comments suggest edit

Steven Clarke has an interesting post about the usability (or lack thereof) of the Factory Pattern.

In simple terms, the usability issue strikes when a developer knows she needs an instance of object Foo. So she tries to new one up like so…

Foo foo = new Foo();

Unfortunately Foo looks like this…

public class Foo

{

ÂÂÂÂprivate Foo() {}

}

Notice the private constructor? VS.NET’s intellisense dutifully tells her that she can’t create an instance of Foo in this way. So now how is she supposed to create her beloved Foo? The answer is that there’s probably a FooFactory laying around somewhere that’ll do just that for her. So now she has to go rooting around looking for that class, her rhythm and flow being disturbed in the process.

So is the answer to simply throw out the Factory pattern? Dear god no! This is one of those cases where perhaps the IDE could be a bit more helpful. Imagine if we could markup the class like so…

public class Foo

{

ÂÂÂÂ/// <summary>

ÂÂÂÂ/// Try using the FooFactory to create this class.

ÂÂÂÂ/// </summary>

ÂÂÂÂprivate Foo() {}

}

And that comment would show up when trying to directly create an instance of Foo. Wouldn’t that be wonderful? Or for you attribute lovers, maybe an attribute would be a better option.

[Factory(typeof(FooFactory))]

public class Foo

{

ÂÂÂÂprivate Foo() {}

}

Either way, the goal is to give the forlorn developer some help via Intellisense. All that API creators need to do is to add a bit of information to their classes and voila! Intellisense to the rescue. You’ve rescued the usability of the factory pattern.

[Listening to: Victorious - Tiësto - Parade of the Athletes (4:38)]

0 comments suggest edit

If you’re a fan of NPR and KCRW, make sure your voice is heard. The House will soon vote on budget cuts for public broadcasting and the issue is being painted as a liberal vs conservative battle.

I believe it is impossible for a person to be truly objective, but as far as news programs go, I think NPR does a great job of it. I think both sides of the political spectrum appreciate receiving news without the sensationalism and fear mongering so prevalent from its puerile cousin, television news. Here is the letter from KCRW in full…


Message from KCRW General Manager Ruth Seymour\ Dear KCRW Listener,

I am writing you about an unfolding crises in Congress with regard to public broadcasting. Proposed funding cuts now before the full House pose a serious threat to public radio and television – and to KCRW.

The proposed cut is 25% to KCRW’s CPB grant this October and next October as well. Moreover adding the proposed additional cuts to PBS childrens’ programs and station digital conversion – the total reduction adds up to a whopping 45%!

Facility funding, which provided oportunities for stations to modernize and extend their service has already been zeroed out. These are the grants that helped KCRW purchase it’s first modern transmitter in 1979 and launch NPR’s Morning Edition. Later they enabled KCRW to extend sevice to Ventura and the Antelope Valley.

If these cuts stand, KCRW may lose over $1,000,000 from its operating revenue. This would severely impact KCRW’s local programming and our ability to sustain NPR.

The Corporation for Public Broadcasting is the independent organization created by Congress to support public broadcasting and act as a heat shield against political interference. But now, ironically, the Corporation itself is providing the heat.

Chairman Ken Tomlinson has politicized matters by framing the issue of balance on news programs as liberal versus conservative. We vehemently object to this characterization which is intended to put public broadcasting on the defensive and influence program decisions.

  • We cherish our editorial independence and the political diversity of the audience we have attracted.
  • We believe in objective journalism, free from political constraints.
  • While we welcome constructive criticism, we reject partisan judgements masquerading as impartial analysis.

We can’t reverse the funding cuts by ourselves. We need your help.

THE MOST IMPORTANT VOICE IN PUBLIC BROADCASTING IS YOURS!

Please register your opinion by contacting your Congressional Representative right away.

The full House votes next Thursday or Friday.

Find your Congressional Representative at:\

http://kcrw.convio.net/site/R?i=wkbWt29jsWNpftH33vy4eg.

Sincerely,

Ruth Seymour\ KCRW General Manager

Visit KCRW.com for additional information and background:

0 comments suggest edit

Lemmings Dare may singlehandedly be responsible for delaying Longhorn, VS.NET 2005, Yukon and many other products as legions of programmers (Microsoft and otherwise) lose productivity by spending their time playing DHTML Lemmings, a faithful javascript reproduction of the classic game Lemmings.

Lemmings is probably one of the most popular games I’ve never played until now. It is quite addicting.

0 comments suggest edit

You know what, I do want to express myself, okay. And I don’t need 37 pieces of flair to do it.

Sand SharksNo. I need a Flickr Badge! For those of you reading this from an aggregator, you’ll need to take a step out of the comfort of the aggregator into the scary world of “web browsing” and view my page from a browser to see the flickr badge on the right.

I know, I’ve gushed about Flickr in the past, but I like how easy they make it to integrate into your own website. They also allow you to put up a a nifty Flash version of a badge, but I settled for the simple HTML badge.

Now if you’re concerned about such things as XHTML validating markup, you really need to quit being so anal and get a life. Having said that, let me show you some small tweaks you’ll need to make so that your flickr badge validates as XHTML 1.0 Transitional (I haven’t tried strict yet). Us anal types can’ go around with invalid markup, now can we?

When you create your badge, Flickr will give you some code to inject into your web page. The first step is to take the style element and either move it inside the head element of your page or scrape its guts and slap them inside a css file.

After that, you’ll notice that there’s a script tag just before a tr tag. That tag essentially is a javascript repeater that repeats the following tr block. If you move it, you break the badge. Unfortunately, it doesn’t validate as is so I haacked it (get it? “haacked it” As in hack? Oh Never mind) by placing the script within a caption element.

Finally, I went through and replaced all the ampersands within the URLs with &amp;. After that, voila! My homepage is back to being valid XHTML 1.0. Do I get a trophy or win prizes for this work? No. But I do get to sport this nifty piece of geek flair. Valid XHTML
1.0!

0 comments suggest edit

From the Lessig blog I learned that Microsoft is releasing its spec for “Simple Feed Extensions” under a Creative Commons Attribution-ShareAlike license, often referred to as a “CopyLeft” . People are free to modify and redistribute the spec so long as the modifications are licensed under a similar license.

This shows a couple things about Microsoft. First, that it is not (and probably never has been) a mono-culture. Secondly, that groups within Microsoft get it when it comes to RSS and know how to play nice. Bravo!

0 comments suggest edit

RSS Now repeat after me, “RSS is designed to be extended.”

Good. Now repeat it again. It’s old hat that Microsoft has engaged in some perhaps anti-competitive practices in the past, often referred to as their “embrace and extend” philosophy. But embracing and extending isn’t always a bad thing.

Of course, I should expect a knee-jerk reaction against the announcement from the Slashdot crowd, but it seems they’re not the only ones up in arms.

What’s interesting about these reactions is the amount of misinformation and ignorance being spewed forth. Suddenly, “extend” has become a derogatory label. Yet these very same people will laud an application like Eclipse for its…gasp!…extensibility (and rightly so).

In this case, it’s hard to find a shred of so called “evil” in this announcement by Microsoft. They’ve chosen a CopyLeft license for Pete’s sake! You don’t get more open than that. You even have Lawrence Lessig applauding this, remember him? He“s the lawyer who helped the DOJ mount its Supreme Court showdown with Microsoft.

Face it folks, you’re just wrong this time. Microsoft releasing extensions to RSS is not going to be the death knell for RSS. An extension does not change or make proprietary the original RSS specification. As I said before, RSS is designed to be extended. Anyone can extend RSS. Heck, even I proposed an RSS extension, albeit one that gained just about zero traction (although I may sneak it into Subtext just to satisfy my megalomaniacal urges).

0 comments suggest edit

Just curious if any of my fantastic readers (or Google searchers, welcome. Nothing but love for ya) have experience with using Quickbooks Online. If so, let me know in the comments what your experience with it has been. Thank you.

subtext 0 comments suggest edit

I’ve been intentionally quiet about how Subtext is progressing (apart from a couple minor posts on how to obtain the code via CVS). My reticense is certainly not from lack of excitement or enjoyment of the project. Working on Subtext has been about the most enjoyable software development project I’ve ever had the pleasure to work on. So much so, that I’ve fallen a bit behind on my “real” work. Unfortunately this has caught up to me as I now have two projects with a potential third not far behind to work on (Yes, I know. A good problem to have, so quitcher belly-aching). This is very exciting for me as it may herald the beginning of a company. But it also means I need to slow down on Subtext a bit.

The reason I have been so reticent about Subtext up to this point is that we have not yet had a release. It was suggested to me that I probably should’t have waited to make the original Subtext announcement until I had a first release. This is definitely good advice for one who is starting an open source project. However, it may have helped in my case that I was building on an existing project familiar to many. And the few who did jump at the chance to help have been invaluable in what progress we’ve made so far.

What progress you ask? Well as you can see in this post, we are making great progress in having a nice logo. This is not the final logo, but probably really close. As you know, if a project has a nice logo, the code must really be nice. ;)

Subtext is progressing nicely in other areas too. So much so that I upgraded my blog to Subtext after a particularly withering comment spam attack. Subtext hasn’t yet completely eradicated comment spam, but it definitely has made a difference already.

In any case, I hoped not to talk much about it until we did have a release, but here I am anyways blabbing my mouth fingers. The goal of the first release is to generate excitement about the project and have many more contributors help with the next release. By talking about it now rather than waiting, I hope to try and encourage people to contribute before the first release. As my involvement declines for a few months (hopefully at most), I hope to have others pick up some of the slack and carry the torch sub forward.

Project Website\ If you’re interested in tracking the progress of subtext, check out our new project website at http://subtextproject.com/. It is definitely a work in progress, but it has plenty of instructions for how to get the latest source code and how to contribute. Not only that, the site itself is in our CVS repository. So if you want to contribute to our documentation efforts (please! please!), you can submit patches to the project site.

Roadmap\ Also be sure to check out the updated Roadmap.

Well that’s it for me. I spent today on some Subtext housekeeping to clear the way for others to make some nice progress. I’ll probably be much more quite for a few months, though I will respond to emails and such and continue to try and guide the process. It’s been and continues to be fun sailing.

0 comments suggest edit

Geolocation Anybody out there use a geolocation service they are happy with?

In case you’re unfamiliar with the term (and thus unlikely to be able to answer my question), Geolocation is the process of converting an IP Address into a geographic location. I think many services simply provide a database of ip address to geographic locations.

Also, how do these services handle AOL? Would every AOL user appear to be coming in from Virginia? Thanks if you have any insight!

0 comments suggest edit

In a recent post I outlined step by step how to obtain the source code for Subtext as a non-developer. Well I was a bit sloppy and made a couple of mistakes in the post (now corrected).

However, I feel a bit bad about it. It’s not like me to be so sloppy and give incorrect information. I decided I must pay penance! These instructions apply to those who want to look at the source code on a development machine.

The Easier Way!

I created a simple batch file you can use to execute the CVS command for you. So my updated steps are:

  • As before, make sure you have TortoiseCVS installed.
  • Create a database in SQL Server named “SubtextData” and make sure your database server has an ASPNET login.
  • Create an ASPNET user using the ASPNET login for the SubtextData database.
  • Download and unzip the batch file to your projects folder (for me, I would place this file in my “c:\Projects” folder.
  • Now double click the batch file.

If you install TortoiseCVS in a location other than your program files, you will need to modify the batch file to point to the correct location.

When you run the batch file, it downloads all the source code from CVS and then runs a downloaded script named “CreateSubtextVdir.vbs” that will set up a virtual directory in IIS pointing to the correct location. All you have to do is compile and browse to http://localhost/Subtext.Web/.

Again, I hope this makes it easier to grab the latest bits and play around with it.

[Listening to: rez/Cowgirl - Underworld - Everything Everything: Live [IMPORT] [LIVE] (11:47)]

0 comments suggest edit

spam I can have a very filthy mouth when pissed off. Take today for example, my dog was witness to a blistering stream of profanities as I found that my site was down. I was hit with a torrent of comment spam like nothing I’ve seen before.

Since I have my blog configured to send me an email when someone comments, the mail server was trying to send out 500 messages in five minutes. At least according to my hosting provider who turned off my site in response to the massive flood of email. All in all, the spammers posted over a thousand messages in a very short while.

This of course prompted me to perform an emergency upgrade of my blog to the latest unreleased version of Subtext. I wasn’t quite ready to perform this upgrade as I was hoping to get a few more comment spam fighting features implemented, but I was getting tired of the bombardment.

In the process I fixed a few bugs here and there, mostly related to the difference between developing on your own server but being hosted on a shared server.

At least now, I can throttle comments so that too many don’t come in all at once. This particular storm of comments appears to have originated in China (at least the comments and urls were in chinese). I think I may have to post a few posts about freedom, democracy, and the American way in order to get my blog banned in China. ;)

[Listening to: Life in Mind - Paul Oakenfold - Global Underground 007 New York CD1 (4:48)]

0 comments suggest edit

I’m in San Francisco for a working meeting for a client. We’re doing a bit of project planning and working through the specs and schematics. The thing I love about San Francisco is I never have a bad time, even if I’m only here for two days and one night.

Last night, my buddy Micah took me, his sister, and her boyfriend out to a nice bar/club named “Milk”. The DJs mixed it up with a bit of neo-soul, hip-hop, etc.. and we closed the place down. Afterwards, I had real trouble getting to sleep, finally snoozing at around five AM.

I’m so tired at this point, my head can’t even make sense of it. I feel like I’m walking in an alternate world than everyone else. Like I’m the one black and white character in a color TV show. The slight bit of tunnel vision doesn’t help either. And no, I did not take any “foreign” substances last night, unless you count just a tiny eensy weensy bit of alcohol.