Saturday, January 31, 2009

Pimp my code ;)

In my previous (hastily written) entry, I tried to show how difficult it was to extract an undetermined URL from a string of text with the traditional FIND / MID functions in Coldfusion, and alluded to using Regular Expressions as a possible solution.

This is going to be a pretty neat trick, particularly since I know less about RegEx than I do about unicorns. ;)

I had hoped to find a copy of Ben Forta's book on the subject during a trip to my local bookstore, but no such luck. Oddly enough, there didn't seem to be any books available on RegEx in the store-- everything had to be ordered online. They did happen to have the O'Reilly Pocket Reference to Regular Expressions, though-- and I found a two page list of "recipes," RegExs put together for specific purposes, such as extracting email addresses, URLs, etc.

So, I copied the recipe for the URL down, convinced I'd found the solution to our problem.

Yes, I know-- naive of me. ;)

The problem with the O'Reilly recipe is that it uses characters that have special meaning in ColdFusion, such as the pound sign. Once I figured out how to escape the pound sign, it told me the parentheses were unbalanced. Troubleshooting the recipe was getting to be a major headache, so I wound up Googling for a RegEx specific to Coldfusion for extracting URLs . . .

and wound up at Ben Forta's blog. (Yeah, I know-- like I should be surprised!?)

Anyways, Mr. Forta offered a RegEx that works with both Javascript and Coldfusion to validate a URL-- which I've used in the REFindNoCase function example below. It's far from perfect, gentlemen-- at this point my code fragment can only find/extract the first URL in a text string, and I'll need to figure out some kind of while loop to make certain every URL has been extracted. But it's a start, right?

We start with our test string, feel free to customize for your own testing purposes:

<cfset tweet = "I like google http://www.google.com better than I like Yahoo ( http://www.yahoo.com ), but that's just me!">

Just displaying the string when the page runs, so everyone can see what we start with.

<cfoutput><p>#tweet#</p></cfoutput>

If you use the last two optional parameters of the REFindNoCase function, you can tell the function at what point in the string it should begin its search (1st character by default) as well as tell it to return a structure that contains two bits of information we need to extract the URL: the position of the first character in the match, and the total length of the matched string.

<cfset results = REFindNoCase("https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?", tweet, 1, "True")>

Then we just use the POS and LEN bits with our MID function to print out the match!

<p><cfoutput>#Mid(tweet,results.POS[1], results.LEN[1])#</cfoutput></p>

We could theoretically pass the extracted string to an API (to TinyURL, for instance), or ROT-13 it, or perform whatever arcane manips we want at this point, and then a simple REPLACE function will be sufficient to insert the modified URL back into the original string-- after all, once we've extracted the URL, we know exactly what it is now.

But, there is one interesting wrinkle I should mention. I've dumped the results variable that the REFindNoCase function generates so we can look inside of it (see below):

<cfdump var="#results#">

See how results actually contains two entries for POS and LEN? That means, I think, that the RegEx is actually finding two matches overlapping, namely http://www.google.com as well as www.google.com.

Replacing the 1 in the indexes of the arrays above with 2 seems to confirm that hypothesis.

Thursday, January 29, 2009

The URL swapping Gedankenversuch

Tip of the hat to Mr. D. H., whose Twitter question (shown below) inspired this entry.

"How could I search a string for urls, if found, do something, then replace the new url?"

I'll be the first to admit I'm not the world's greatest Coldfusion coder, but this problem is more difficult and more subtle than you'd imagine. The "replace the new URL" part is actually fairly easy, with Coldfusion's replace function. But first you need to successfully extract the original URL from a string of text, such as a twitter entry.

<!---
NOTE: this code assumes . . .

A) all valid links must start with http://
B) links have no gaps (e.g. http://www.exam ple.com/)
C) only one link per a text string, for now, please! We can add more later.
--->

<cfset tweet = "I should update my blog http://anerroroccurred.blogspot.com more frequently.">

<cfset startsAt = #FindNoCase("http://",tweet)#>

<cfif (#startsAt# IS 0)>
<!--- we can't find any URLs in this text, so do nothing --->
<cfelse>
<p>URL starts at: <cfoutput>#startsAt#</cfoutput></p>
<cfset endsAt = #FindNoCase(" ", tweet, #startsAt#)#>
<cfif endsAt IS 0>
<cfset endsAt = Len(tweet)>
</cfif>
<p>URL ends at: <cfoutput>#endsAt#</cfoutput></p>
<cfset theURLis = Mid(tweet, #startsAt#, (#endsAt# - #startsAt#))>
<cfoutput>And the URL is: #theURLis#</cfoutput>
</cfif>

Looks promising, right? That is, until you realize that people do all sorts of crazy things with URLs in text.

For example:

"My blog is at http://www.example.com. You should check it out!" (That period after the URL means trouble for our code above!)

"I have a blog entry (http://www.example.com/firstServed.htm) you might enjoy." (Great, now we have to anticipate parentheses!?)

Clearly, the find and mid functions alone aren't gonna be robust enough to handle our challenge. We need some serious black magic.

Thursday, January 22, 2009

Coldfusion is dead; long live Coldfusion

They say: "Nobody uses Coldfusion any more."

Well, almost nobody, except for Adobe, and maybe . . .

1) The US Federal Government: The Senate's inaugural site, Food & Drug Administration's Peanut Butter recall info site (pretty hard to get more topical than that!)

2) New York City's Tourism Organization web site (search engine and calendar powered by CF)

3) Crayola's Official site - yup, Coldfusion & coloring, who knew?

4) The Mayo Clinic - these guys are doctors, so I think they're pretty qualified to determine if something is dead or not.

5) MySpace - Coldfusion and Fusebox, it turns out.

6) The American Kennel Club - Who's a good puppy? Who's a go . . . erm, nothing to see here. Move on to the next item, please.

7) The Peace Corps - Travel, see the world, and help people.

8) AT&T Labs Research Division - Can you query me now? Good! ;)

9) NetLingo not only uses it - they define Coldfusion as well.

10) Urology Health.org - Take my advice, don't get into a pissing contest with a wizz wiz.

Monday, January 19, 2009

iPod Shuffle with green/orange blinking lights

I'm feeling a slight sense of deja vu. Lately, I seem to spend my time and energy fixing things. It's nice on some ways, because at least I can still set things right-- but at the same time, I feel like it gets in the way of me being creative, learning new things. And yet, here I am, searching for material for a blog entry, and what comes to mind except "Maybe I should document how I got my iPod Shuffle working again after it stopped working?"

And see, the deja vu would be because a million years ago, when I first started blogging (think before Google bought Blogger, k?) the predominant topic was the fixes and workarounds I came up with to make things work properly.

No wonder no one reads my blog then. ;)

I have a first generation iPod shuffle that suddenly stopped playing songs/podcasts entirely. When you hit the controls (play, skip forward, skip back, pause, etc.) the green and orange lights blink in an alternating pattern. According to documents I found while researching this problem, it could be anything as simple as a battery in need of recharge to as dire as "the green and orange lights of death!"

No, seriously-- that's what they called it. What, you thought I made that up?

Anyways, yes, it would have been the perfect excuse to go out and buy a new iPod or other MP3 player-- but money's been a little tight lately, you know, between the bathroom renovation and Christmas. So, I figured I'd take a crack at fixing the iPod I had first.

Basically, I was able to plug it into the USB port of my iBook, and it saw the contents of the music partition as well as the contents of the data partition. (I have my iPod shuffle "split" for Disk Mode so it can store files and documents, like a traditional USB thumbdrive.) I was able to copy all my files off of the iPod in the Finder, and then reinitialized it from within iTunes.

In addition to warning me that I'd lose all the files and media, it also (after I told it to proceed) reapplied the iPod firmware update. I typed in the "new" name for my iPod Shuffle-- which I set to my phone number, just in case I ever lose the darn thing. I decided not to activate Disk Mode at this time, and just let it store music. I copied two MP3 files across from within iTunes, plugged in my earphones, hit the play button-- and everything worked just fine.

Saturday, January 17, 2009

Work on What Matters - Great Idea, but How?

I've been hearing extra buzz lately about Tim O'Reilly's "Work on What Matters" theme, particularly now that it coincides with a paradigm shift in the administration of the US Federal Government.

Although I apparently know how to work with others, I don't know how to get others to work with me. I could bore you with examples, but what's the point? You either read it and understood it immediately (because you are there in the same boat with me), or you read it, didn't understand it and never will because it has never happened to you and never will.

I spend a lot of my time and energy helping other people realize or get closer to the end result that is important to them, but whenever "my turn" comes up-- well, it's like people hear their mother calling them home for dinner or something! They can't be bothered to listen to my point of view for three seconds.

Case in point, remember in the "early" blogging days a tool called "Greymatter?" I tried offering a suggestion to help improve that tool during a major revision period, and was pretty much kicked in the teeth by the "in crowd." The simple truth behind the demise of Greymatter is that the core team decided they knew what was best and they were mistaken. The competition (Blosxom, Movable Type, etc.) focused on things like syndication feeds, trackbacks/writebacks and features that dovetailed nicely into the entire social networking paradigm that would spark "Web 2.0." Greymatter's core team decided to show what song you were listening to when you were writing your blog entry; small wonder everyone migrated off that platform then?

So, Tim O'Reilly, Seth Godin, the conjoined ghosts of Abbie Hoffman and Timothy Leary, or some expert on human nature-- please tell me, what are hard-working, passionate, creative and technologically sophisticated people supposed to do when they are repeatedly and deliberately ostracized by communities or movements because the in crowd/clique has decided to adopt a xenophobic, gated community outlook?

(sigh) It could be worse, I suppose. At least no one is trying to kill me because of my skin color.

Saturday, January 10, 2009

The Component Conundrum

I know, I should write Coldfusion applications with components as the building blocks. I get it, really-- it's better for maintenance, code reuse, separates your content from your business process. Seriously, I understand how important it is.

Too bad I can never get it to work. :(

See, here's my problem. Let's say I want to write a CFC (Coldfusion component, for the uninitiated) that accepts an employee's ID number, queries Active Directory, and returns the employee's name, phone, email, and basic contact info. It sounds like a great idea, doesn't it? Set it up as a component, accept three arguments, the ID number, and the user id and password of the account to use for LDAP. Then, you can leverage and reuse it for all your application, or your team-mates can use it in their programs . . .

Oh, um, wait, that's weird-- the field in Active Directory for employee ID number seems to be empty. Not sure what that means. Hang on a sec, let me call the Tech Support folks.

(ten minutes later)

Well, it seems that whoever set up our Active Directory felt that using the field called Employee ID to actually hold the ID numbers was too generic and needed to be more proprietary or secure or . . . something, so they actually keep that information in ExtensionAttribute22 instead. And now, we have a component that only works with your specific and unique implementation of Active Directory.

I know, it's a grossly oversimplified example, but I think it makes the point. It's hard enough for those of us who don't think natively in object-oriented fashion to figure out what should be turned into a component, then to plan out the various properties and methods. It's downright demoralizing to discover when we try to implement them that someone has made a seemingly arbitrary change to the configuration of something with which we must interact. I mean, why don't you change the name of the mail server to "Linda" or "Lassie" or "Ficus Green Pearl", while you're at it?

I just want some consistency when I work. Not like I'm asking you to get me sharks with friggin' lasers attached to their heads.

Wednesday, January 7, 2009

Linux and Windows

Sometimes one of my Windows-using friends will ask me why I use Linux. They usually don't ask because they want to learn more about Linux, but would rather start a debate about why "their favorite" operating system is better. Personally, I think a "favorite OS" is ridiculous. It's a tool to help you accomplish something. Do you have a favorite drill bit? Or a favorite subway ticket?

However, in the interest of provoking those same aforementioned Windows-using friends, I pass along the following observation:

My Windows XP work laptop has received Windows updates for the past three days, and gave me a "C:\ drive is low on disk space" warning this morning as a result. I wound up having to delete 2 GB of space.

My Ubuntu eeePC received updates after 21 days of forgetting to check, and afterwards I actually wound up having roughly 7% more free disk space afterwards.

Yes, those Ubuntu developers are amazing. :)

Monday, January 5, 2009

Steve Jobs - what's private and what's public?

Apparently Steve Jobs made some disclosures today to combat the rumor-mongering about his health. I frankly don't get it-- and maybe the truth is I don't understand it because I just don't want to do so. The "stockholders have a right to know" argument just doesn't hold water with me because if you chose to invest in a company that depends upon the health and well-being of a specific, single individual to flourish-- well, much as I hate to say it, you made a bad choice.

It's funny, but I find myself struggling to write about this. If anything, this seems like the perfect bizarre intersection of the three things about which I'm most passionate. You have a company that produces innovative, ground-breaking *technology*-- and it engages the consumer in distinctive, brand-building ways that change the paradigms we live within (sounds like *psychology* to me!)-- but stockholders/fanboys/analysts all appear to be worried that the stock and the performance of the company hinges completely upon the health of its (CEO? Shaman? Messiah?).

It's simultaneously fascinating and revolting-- we've got plenty of financial fraudsters out there that no one gives a second glance (three letters to the SEC! Three!??), who bilk people and philanthropic organizations for millions of dollars, and yet we feel we have the right, the entitlement to compel personal health disclosures from a guy who's really busted his ass to make the world a better place.

Friday, January 2, 2009

Camera and Batteries

I've been having the strangest problem with a Pentax camera recently. It's a very nice camera in terms of features and pixels, but it DEVOURS batteries. Or, at least, I thought it did.

Basically, if I recharge my NiMH batteries and put them in the camera, but don't use it right away-- when I get around to turning the camera on hours later, it will complain that the batteries are depleted. Okay, it was just a quirk of the camera I had to remember-- for some reason, it uses up batteries even when it isn't on. Not a big deal, just remember to carry the batteries separately in the bag and put them in right before use.

Except, when I was on vacation, I forgot to take a pair of batteries out for overnight. And the camera worked fine the next day. So, obviously the camera isn't to blame. At this point, the trouble-shooter in me has become intrigued. Perhaps it's the batteries? After all, the batteries I'm using have been through lots of cycles, charging and discharging. Maybe they just can't hold enough energy to reliably power the camera.

So, I buy brand new rechargeable batteries, charge them up over night-- and the camera eats them up in seconds. I charge the batteries again, figuring maybe I didn't leave them in long enough. At first, the camera is happy-- and then, less than 12 hours later when I go to actually use the camera, the batteries fail on me again.

At this point, I'm starting to get a little peeved. Brand new batteries, and the camera worked once with another set of the older batteries. So, what's left? The only other piece I can think of in the equation is the charger.

I wound up borrowing my mother's battery charger for a bit, recharge the batteries, and so far the camera has been working just fine.

So, it's got to be the charger. Right? Not so fast, because there's a curve ball. I successfully used the old charger when we were away on vacation. The real test is for me to use the old charger, with the old batteries, but on a different electrical outlet.