Add to Technorati Favorites



 

...where sanity comes to die.
Visit my blogBlur the lines between genius, insanity, and utter stupidity.WALDOLand Music CentralDevelopment WorkAbout MeContact MeWALDOLand Site Map
 

 Monday, March 24, 2008

Well it's about goddamn time!

I get home and flip on my laptop. I look up and there's an alert from Apple. I have new downloads available. I open the dialog and, voila. Safari version 3.1 (525.13) is ready for download!

Apple finally released a version of Safari for Windows that doesn't crash INSTANTLY!

Yay.

Thank God. It's been months since Apple released a version that didn't crash within 3seconds of starting up. I haven't been able to do successful Safari development or testing in months. That's really great when you're about to release a large scale production website. Uh, we hope it works.

Everybody and their momma would tell Apple about it. Apple would keep releasing Safari like it worked. We'd all fire up Safari and guess what? Same thing.

Apple: "It works now."
    Users: "Uh, no it doesn't."
Apple: "OK, it works now."
    Users: "Uh, no it doesn't."
Apple: "How about now?"
    Users: "Nope. Nothin'. Still broke."
Apple: "Now?"
    Users: "Nada."
Apple: "I said it works. Now leave me alone!"
    Users: "Hello? Is anyone there?"

Labels: , , ,

 Saturday, January 26, 2008

Saw this and thought it was awesome

HTML tattooTo all my tech geek friends, you should find this hilarious.

I was surfing the web and stubled across this image of a dude who has HTML markup tatooed on the back of his neck. More specifically, a closing </head> tag, followed by an opening <body> tag.

To quote Desirea, awesome. :)

Labels: , , , ,

 Sunday, December 16, 2007

Facebook vs. MySpace

You know, Facebook kicks so much ass over MySpace.

MySpace is good for a public identity. Like if you're a band or a comic or a celebrity or something and you need a web presence, MySpace is the way to do it. It's a quick way to get a feature-laden web site up for free with built-in publicity. Easy. Simple. Done.

Facebook on the other hand is much better for the personal level of social networking. In stark contrast to MySpace, you're not riddled with random friend requests, otherwise known as MySpace Spam. Friends on Facebook are grouped by their affiliation with you (high school, college, job, etc.) making them much easier to find because they are targeted searches. you will actually have a network of your friends. MySpace is kind of a free-for-all. Any random schmuck will try to be your friend.

Facebook is MUCH cleaner, prettier, more functional than MySpace. MySpace offers its users the ability to customize their layout, but that usually leads to someone putting as much garbage as they can in a layout, which then makes the layout slower, offensive, or non-functional to the casual viewer. When I just want to add you as a friend, I don't want to sit and wait for your layout to load, with your f***ed up graphics and your music player blasting Omarion at me. I just want to add you ass a friend. Some of m best friends on MySpace have the poorest choices in layouts.

Facebook has the ability to add and or design fun web applications which can be installed like plug-ins to a user's profile. This alone creates business/developer/strategic partnerships with Facebook, something MySpace is currently unable to capitalize on.

Facebook is geared much more to Web 2.0. If you don't know or understand what Web 2.0 is, then don't bother reading this section. Rather than having pages laden with large blocky advertisements and javascript errors like MySpace does, Facebook is slick, easy to use, easy to navigate, and takes advantage of those things that should be used when designing in Web 2.0, like AJAX. The bottom line is that Web 2.0 is supposed to be all about the user experience (usability). MySpace is clunky kludgy, hard to use, riddled with errors, and undergoes maintenance nearly every other week, which usually doesn't fix some of its major issues. Facebook on the other hand is clean, cutting edge, feature rich, functional, and very rarely (although I have spotted a few, no question) has errors. Or at least has significantly fewer errors than MySpace.

I've even heard multiple companies (including the one I work for) including Facebook applications as part of their overall product base. How often does that happen? Although, granted a lot of media (TV/Film/Radio/Music/Comedy) includes MySpace as part of publicity campaigns, so I will give them credit for that.

It seems like you could break down your major social networking sites like this:
Professional: LinkedIn
Media/Entertainment: MySpace
Personal: Facebook

Facebook just seems like more of a personal touch to me. Although yes, I will continue to use both, I'm going to begin gravitating more toward Facebook.

Labels: , , , , , , , , , , ,

 Tuesday, October 30, 2007

No longer supporting legacy development

As I'm sitting here reinstalling software on my laptop, I've made a decision. In order to save hard drive space, I have decided not to install any Visual Studio 6 components or Visual Studio 2002/2003 components. Therefore I will no longer be supporting any legacy app development. All of my applications that were built with earlier versions of the studio will be ported to Visual Studio 2005 if code was not already developed in parallel. Visual Studio Add-Ins will continue to have backwards compatibility with 2002/2003 versions, but will be built by, deployed by, and targeted to Visual Studio 2005/2008.

Labels: , , , , , , ,

 Sunday, October 28, 2007

Well I fucked up my PC again.

Here I am on a Sunday night, backing up my files from my laptop yet again. I have to reinstall my OS because some shit I installed trashed my Wireless adapter, causing my services (services.exe) to crash every time I boot up. F-Guk! I have another three days of reinstalling software to look forward to.

What prompted me to install this crap ass software was me getting banned from allmusic.com. I needed something to disguise my IP address. I should have just went with TOR like everyone else. Instead, I went with the first thing I found on Google and tried to download a cracked version which had several trojans in it. My Anti-Virus software stripped out the trojans like it should have, but left the installer in a fucked up state. Dammit. Should have known better, but this is why I do this type of shit on MY PC.

Oh well. Maybe this time I won't install quite so much shit. I may actually have room for my music library (which is well over 45 GB) and my software to coexist on the same box. At some point, probably not until after Christmas, I will buy a new laptop with a substantially bigger hard drive. I'm going to try for 200 GB at least. I'll probably end up selling my laptop to Alan for cheap, or just giving it to someone who needs a laptop.

Labels: , ,

 Saturday, October 27, 2007

Banned!

Summummabitch!

As some of you know, I've been scouring content from the web to make my MP3 collection pages more SEO friendly. So of course with my huge collection of songs it would take until the end of the next millennium to gather reviews, artist bios, and lyrics manually. Naturally, I built a tool.

Now of course, my tool has to be as unnecessarily sophisticated as it can be, which means I'm doing major website scraping, multithreading, thread pumping and dynamic throttling. I ran my tool for every artist/album/track in my collenction against AMG and other sites. Over 30,000 website hits in a matter of a few hours. Collected everything I could. Sweet.

Of course as I'm reviewing my results, I realize there's a major bug in my screen scraping routine. D'oh! I go to run my tool again, and suddenly, I get no results. I check my search result manually and this is the message I get any time I do a search on AMG from my home laptop:

Through traffic monitoring of our websites we have identified your IP address accessing allmusic.com at a rate and speed inconsistent with the noncommercial and personal use permitted by our site's Terms of Service. As a result, further access to allmusic.com has been denied. Because IP addresses can be shared by numerous users, your access may be being denied based on the aggregate use of your IP address rather than your own individual use. To ensure that this is not the case, simply create your own individual user account by becoming a Registered Member of allmusic. [Click on the “Register” button in the upper right hand corner of the home page.] Once you’ve become a Registered Member and are logged in, you will once again have full access to allmusic, and will continue to have access, as long as your usage remains consistent with our Terms of Service. If you are already a Registered Member of allmusic, simply ensure that you are logged in when you use the site. Thank you. - xxx.xxx.xxx.xxx
Dammit!

Though technically, it is for personal use, I suppose I could see how after reviewing their logs they could interpret my usage as a Denial of Service attack. Come on, what If I were a search engine spider? Hehe. I just thought that was way too fuckin' funny! Now of course, you know me. I'm not going to let this stop me, but this was great! Hah!

Labels: , , , , ,

 Thursday, September 20, 2007

Aptana Javascript IDE

Someone at work asked me the question "Do you know of any good javascript editors out there with documentation and intellisense built-in?"

Visual Studio has never been really smart about javascript. Yes, it does provide intellisense, but only at a very minimal level. Only if you are typing within a <script></script> block contained in an HTML or ASPX page, does it provide you with anything, and even then, InterDev left a better footprint of intellisense. VS doesn't validate syntax, or even precompile classes in javascript. VS is very limited. Perhaps in future versions, Micro$oft will

Believe it or not, I didn't have an answer for him. I had been doing javascript for so long (almost 10 years now) that I didn't really have a personal need for intellisense. Everything I put together, I usually knew what I was looking for. Javascript has just become so native for me, that I rarely have to look up documentation for a method or property.

But in the spirit of being a good sport, I decided to see if I could find him one. I did a little research on the net. I came across a few, that looked like they had potential, but I wasn't really love with any of them.

That is, until I stumbled upon Aptana.

Aptana is a full-blown javascript IDE with massive intellisense, syntax validation, and precompilation which lends itself to intellisense. It totally rocks, dude! Nice. But don't take my word for it. Go check it out for yourself.

http://www.aptana.com/

Labels: , , , , , ,

 Wednesday, July 11, 2007

Why didn't I think of that sooner?

I had been spending a lot of time working on my website. I can remember a good portion of time went into writing an HttpModule to identify pages generated by Blogger and apply an HttpFilter to produce server generated content based on static markup in those pages.

A brief explanation...

Blogger (the way I have it configured) generates HTML pages for each post, organized by date, an index HTML page for the home page, archive pages, etc. All of them static HTML, generated from a template. Then Blogger FTP's them up to my site. Simple for static content, right?

My HttpModule knows, through its own configurations, which folders on my site contain blog HTML files. If one is requested, it attaches an HttpFilter which scours the content using Regular Expressions, looking for markup that I designate. When it finds that markup, it replaces it with dynamic content, such as UserControls containing menus, Ad rotators, links, etc. It added a little overhead to the processing time of rendering a static page, but for the dynamic content, it was worth it for me.

I spent a couple of weeks building this very slick solution. It ostensively converted static content to dynamic.

A couple of days ago, while working on another section of the site using a Master Page, it hit me. Blogger lets me configure the names of files that it generates. It doesn't HAVE to be .html. Why couldn't it be .aspx, inherit a generic BlogPage class, and use a Master Page?

Holy crap what a great idea! Why hadn't that come to me in like a year? That would save me so much time and effort in updating my blog template.

I used to use a Master Page (several, actually) for the rest of the site, fish out the static content for a page once it was rendered, then apply it to my blog template so that my posts could look and behave like the rest of the site. This meant that any change to my Master Page, or to configurable dynamic content would mean that I would have to update the template and republish my entire blog. This also meant keeping a huge amount of static markup in my template which made diagnosing problems that much more difficult.

So I'm sure the question all of you want answered is, "So how do I use Master Pages and blogger content together?"

Well, I'm glad you asked.

  1. Start by creating a BlogPage base class in your App_Code directory.
    Public MustInherit Class BlogPage
        Inherits System.Web.UI.Page

        Protected WithEvents TitleContent As System.Web.UI.WebControls.Literal

        Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            ' Apply the TitleContent's inner Text to the title, overriding the Title
            ' property defined at the page-level

            If ((Not Me.TitleContent Is Nothing) AndAlso (String.IsNullOrEmpty(Me.TitleContent.Text.Trim()) = False)) Then
                Me.Title = Me.TitleContent.Text.Trim()
                Me.TitleContent.Visible = False
            End If
        End Sub


    End Class

  2. Then create a Master page for your blog content.
    <%@ Master Language="VB" Inherits="MyBlogMaster" CodeFile="MyBlogMaster.master.vb" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server" id="head">
        <title>My Blog Master Page</title>
    </head>
    <body>
        <form id="aspNetForm" runat="server">
            <!-- BEGIN BODY CONTENT -->
            <asp:ContentPlaceHolder ID="BodyContent" runat="server">
                INSERT BLOG CONTENT HERE!
            </asp:ContentPlaceHolder>
            <!-- END BODY CONTENT -->
        </form>
    </body>
    </html>

  3. Update your Blogger settings to generate .aspx pages, rather than .html pages
    Blogger settings

  4. Update your Blogger Template to generate ASPX pages (Web Forms with no codebehind) that will inherit from your base page and consume your Master Page.
    <%@ Page Language="VB" MasterPageFile="MyBlogMaster.master" AutoEventWireup="false" Inherits="BlogPage" title="My Blog Page" %>

    <asp:Content ID="BodyContent1" ContentPlaceHolderID="BodyContent" runat="server">
    <asp:Literal id="TitleContent" runat="server" Visible="false"><$BlogPageTitle$></asp:Literal>

    <Blogger>

    <BlogDateHeader>
    <p class="dateheader"><$BlogDateHeaderDate$></p>
    </BlogDateHeader>

    <a id="<$BlogItemNumber$>" />
    <BlogItemTitle>
    <p class="posttitle" id="BlogItemTitle<$BlogItemNumber$>">
    <BlogItemUrl><a href="<$BlogItemURL$>" title="<$BlogItemURL$>"></BlogItemUrl>
    <$BlogItemTitle$>
    <BlogItemUrl></a></BlogItemUrl>
    </p>

    </BlogItemTitle>



    <div class="post-body">
    <p>
    <$BlogItemBody$>
    </p>
    </div>

    </Blogger>
    </asp:Content>


Oh my god! How much smaller is my template now? I don't have to port all that static markup in the template. If I ever need to change something, I can just change the Master Page and have it propogate all the way through every blog item page. Yay! How long did it take to implement? Well, let's put it this way, It took longer for me to write this post than it did to implement this entire solution.

Now of course I now have the problem of search engines having defunct links. Simple fix. I changed the behavior of my existing HttpModule to send 301 (Permanently Moved) HTTP statuses for any requests to the old .html pages to the new .aspx pages, rather than applying the HttpFilter to convert the static content to dynamic. Sweet!

Labels: , , , , , ,

 Tuesday, June 12, 2007

Posing a question

Non-Techies need not read further

Hmmm...

I've been building a VB.Net library for reading ID3 tags out of MP3 files. I'm wondering if I find a version 2 tag, should I completely discount the information found in the version 1 tag?

Should I treat it as "Highest Version Wins", or should I do a type of merge, where if artist is not found in version 2, use the one found in version 1?

Please comment if you have some input.
Thanks :)

Labels: , , ,

 Tuesday, June 05, 2007

New Features Coming Soon!

After spending the last month or two upgrading the infrastructure/architecture of my sites which include waldoland.com and robertmayo.com, I've finally reached the point where I can officially say I'm at a stable release point. .Net 2.0: code complete! Woo Hoo!

As some of you may know, I've been working feverishly on new content and features for my site. I had spent so much time coding, that I forgot to have fun on the site. Of course for me, coding is fun so, there you have it. Here's a sneak peek at some of the new features forthcoming.

  • Hottie of the week
    Every week I'm going to post about who is the hottest little number in music, movies, & television. You can check out a brief bio, vote and rate the hottie.
  • Drunk movie of the week
    Everyone needs to know what the best movie to watch on a Friday night when you're drunk is.
  • MP3 Library
    I'm going to list EVERY track in my vast MP3 collection. Guests will be able to browse and search the tracks in my collection. Registered users will be able to build personal playlists of tracks which I might compile for them.
  • Surveys
    I frequently see surveys out there, for example on MySpace, which are just fun to read. I've decided I'm going to take some of them and share with the world. A preview of one of my favorite surveys is here.
  • Polls
    I'm going to put up opinion polls, shooting for about one a week. Topics would range from personal experiences to the latest trends in media, fashion, & entertainment.
  • Reviews
    I'm going to give my reviews of the latest movies, music, & video games I've acquired. People need to know if things are a good buy or not.

Labels: , , ,

 Friday, February 23, 2007

Locked Assemblies in /bin

A few days ago I had a bizarre website administration issue. I had written an ASP.Net app that inadvertently locked my assemblies in the /bin directory. Granted the obvious, that assemblies in ASP.Net applications are shadow-copied to the Temporary ASP.Net files folder under the specific version of the framework, but my app was special in that it dynamically loaded and inspected the assemblies in the actual bin directory.

In designing the app, I had waited to put the inspection of these assemblies in a separate AppDomain, electing to do that when time permits. Because of this, When I loaded the assemblies in the /bin directory, the .Net Framework keeps a lock on those files for the lifetime of the current AppDomain (until it is unloaded). For working on my local machine, this is fine during development. If anything locks, I can simply run an IISRESET command, which will unload all AppDomains for ASP.Net web applications on my server. When migrating these assemblies to my hosted environment, it was a different story.

Using FTP, I pushed up all my new development work, did a small smoke test, tried my pages and voila! She worked! I went back into development and modified my pages so they load all of these assemblies on a separate AppDomain (which can be unloaded through code). I went to push up my new changes and then it hit me...The assemblies were now locked in the hosted environment!

Well, great! Now I can't push up my new changes, or any other changes for that matter, until the AppDomain which runs my app in the hosted environment is unloaded. This means either calling the hosts on the phone and asking them to do an IISRESET for me, which since this is a shared server, they probably won't do because it would knock off other customers for a few seconds, or asking them to reboot the server, which for the same reason, they also probably will not do. Oh, I'm so screwed.

So I got to thinking. I could either wait for one of these two things to happen naturally, which since one of the founding principles of shared/dedicated hosting is 100% uptime, could be never, or I could take matters into my own hands. I figured there had to be a way to release file locks through code. Seems easy enough, right?

My first challenge was to find a method to unlock these files which would only affect ME. I couldn't be responsible for interrupting someone else's site on that server. My solution had to be isolated to my own application. I started writing a little administrative ASPX-only (no codebehind) page which could perform my task.

I tried using System.IO.FileStream to unlock the individual files. Well, that didn't work because the Framework will sense that the files are already locked BEFORE you even try to unlock them, and throws an exception.

So I did a little research. I found a way to unload a web app and return it to a state just like it was the first time it was run. Call HttpRuntime.UnloadAppDomain(). What this does is clears out the Temporary ASP.Net Files folder for your application. The next time a request is made, it reinitializes the app, shadow copying all the assemblies in the /bin directory to the Temporary ASP.Net Files folder. Cool. You would think that would work. It did not! It shadow copied all of the assemblies, but naturally it doesn't touch the actual assemblies in the /bin directory, which means it didn't affect the locks. D'Oh!

I was growing frustrated. My next step was to do something a touch more drastic that wouldn't be isolated to just me. I was going to programmatically perform an IISRESET on the server. I wished there was a way to do an IISRESET just for a particular LM Instance, but alas, there is not. I would be taking down every internet service on that remote machine momentarily. Fuck it. Let's do it. So I wrote some VB code that would start a Process which would run IISRESET. I tried it, it worked on the hosted server. I was actually rather surprised that the user account which ASP.Net was running under on that server actually had permissions to start a process. Gift Horse -- Mouth -- whatever.

I could see IIS coming down and coming back up. Thankfully it only took a few seconds. Must be a powerful machine to perform an entire IISRESET in like 3 seconds. Alright! I reconnected to FTP and tried to upload my latest DLLs and DAMMIT! Still locked. Sumummabitch! I was really pissed now. I couldn't understand why an IISRESET wouldn't release those file locks.

I did a little more research. The basic principle of unlocking a file that your app did not lock is to get its file handle, get the process which has the file handle open, and use the Win32 API method CloseHandle to release the lock. Well since I did not and could not know what the file handle was on the hosted server, I tried a slightly different method that ultimately worked out for me.

I started thinking I would use the Win32 API to get a list of the processes with open file handles on my files and simply kill them. Then it hit me. You're overthinking, stupid! You know which processes are running ASP.Net. The only processes ASP.Net has ever run under are aspnet_wp.exe (ASP.Net 1.0) and w3wp.exe (ASP.Net 1.1 and 2.0). Fuck it! I'll just kill them. At this point after I had done a couple of IISRESETs on the hosted server, I didn't give a shit about interrupting anyone's services anymore. I was too pissed off.

THANK GOD! It worked. Killing those processes on the server released my file locks and I was able to make my updates. So now I kind of have an ultimate IIS administration tool now. I can provide any task I need from a web page, provided the ASP.Net process account is given enough permission. Here Is a sample of my work.

<%@ Page Language="vb" AutoEventWireup="false" Inherits="System.Web.UI.Page" %>
<%@ Import Namespace="System.Diagnostics" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
  <head>
    <title>IIS Override Tool</title>
    <meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
    <meta name="CODE_LANGUAGE" content="Visual Basic .NET 7.1">
    <meta name=vs_defaultClientScript content="JavaScript">
    <meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
  </head>
  <body MS_POSITIONING="FlowLayout">

    <form id="Form1" method="post"
runat="server">
<asp:Button ID="Button1" Runat="server" Text="Unload AppDomain" OnClick="Button1_Click" />
<asp:Button ID="Button2" Runat="server" Text="Reset IIS" OnClick="Button2_Click" />
<asp:Button ID="Button3" Runat="server" Text="Kill ASP Worker Process" OnClick="Button3_Click" />
<script language="vb" runat="server">

Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
    ' Unload and reinitialize the application
    HttpRuntime.UnloadAppDomain()
End Sub

Private Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
    ' Performs an IISRESET
    Dim si As New ProcessStartInfo
    si.FileName = "iisreset"
    si.Arguments = ""
    si.UseShellExecute = True
    Dim prc As Process = Process.Start(si)
End Sub

Private Sub Button3_Click(ByVal sender As Object, ByVal e As System.EventArgs)
    ' Kills all the ASP.Net processes on the local machine

    ' Collect all the applicable processes. Multiple side-by-side versions of the framework may mean
    ' multiple instances of either aspnet_wp.exe or w3wp.exe

    Dim killer As New ArrayList
    For Each p As Process In Diagnostics.Process.GetProcesses()
        Dim processName As String = String.Empty
        Try
            processName = p.ProcessName
        Catch ex As Exception
        End Try

        If (processName <> Nothing) Then
            If ((String.Compare(processName, "w3wp", True) = 0) OrElse (String.Compare(processName, "aspnet_wp", True) = 0)) Then
                killer.Add(p)
            End If
        End If
    Next
    For Each p As Process In killer
        p.Kill()
    Next
End Sub

</script>
</form>

</body>
</html>

Labels: , , , ,