1. Douglas Crockford: JavaScript Hero

    Douglas Crockford: JavaScriptA week or so ago, I stumbled upon the YUI Theater, while taking yet another look at the Yahoo! User Interface library.

    On the theater page, there are a number of talks from Yahoo!'s Javascript Architect, Douglas Crockford. Crockford is a really smart guy, and if you do any JavaScript development, you owe it to yourself to spend 2 hours watching to his class, "The JavaScript Programming Language."

    I just finished watching the first "Advanced JavaScript" video, and I'm hungry for more (but I do need to sleep )-: ). I'll be watching the others, soon. There's also a DOM series from Crockford that I'll be taking a look at.

    Even if you consider yourself pretty familiar with JavaScript (as many of us do), I don't think you'll find it a waste of time. The guy's incredibly smart.

    (Incidentally, Douglas Crockford is the guy behind JSLint, which I discovered, independently, before he mentioned it in the video. Check that out, too.)

  2. PHP Pie?

    I've often had to manipulate large blobs of text—no, make that many files containing large blobs of text.

    Of course, my IDE can usually handle simple search-and-replace operations, I appreciate the simplicity of the command line interface, on most occasions.

    That's one of the reasons I love working in a unixy environment, I think. There's a bunch of utilities that embrace the command line and take simple input and deliver equally simple output. I've employed sed and awk, in the past, and I still use them to perform some very simple parsing. For example, I can often be found doing something like ps auxwww | grep ssh | awk {'print $2'} to get a list of ssh process IDs, for example.

    But almost anyone who's ever been enlightened to perl pie delights in its power. In a nutshell, I can do something like perl -p -i -e 's/foo/oof/g' somefile from the command line, and perl will digest every line of somefile and perform the substitution. Perl is very well suited to this type of operation, what with its contextual variables and all.

    I updated the code a little, below. You now must explicitly set $_.

    Read on for my PHP-based solution (lest planet-php truncate my post). I've often found myself looking for a PHP equivalent. Not to do simple substitutions, of course, but complex ones. And since I'm most comfortable with PHP, and a I have a huge library of snippets that I can dig out to quell a problem that I may have solved years ago, I've been meaning to fill this void for a while.

    Tonight, I had to come home from a dinner party, early, because my daughter was sick. Too bad, it looked like it was going to be an amazing feast, but I digress. The home-on-a-Saturday-night time left me with a bit of free time to solve one of the problems that's been floating around in my head for who-knows-how-long.

    Thus, I'm happy to present my—at least mostly—working PHP pie script.

    #!/usr/bin/php <?php // Change the shebang line above to point at your actual PHP interpreter $interpreter = array_shift($_SERVER['argv']); $script = array_shift($_SERVER['argv']); $files = array_filter($_SERVER['argv']); if (!$script) { fwrite(STDERR, "Usage: $interpreter <script> [files]\n"); fwrite(STDERR, " Iterates script over every line of every file.\n"); fwrite(STDERR, " \$_ contains data from the current line.\n"); fwrite(STDERR, " If files are not provided, STDIN/STDOUT will be used.\n"); fwrite(STDERR, "\n"); fwrite(STDERR, " Example: ./pie.php '$_ = preg_replace(\"/foo/\",\"oof\",\$_);' testfile\n"); fwrite(STDERR, " Replaces every instance of 'foo' with 'oof' in testfile\n"); fwrite(STDERR, "\n"); exit(1); } // set up function $func = create_function('$_', $script .';return $_;'); if (!$files) { // no files, use STDIN $buf = ''; while (!feof(STDIN)) { $buf .= $func(fgets(STDIN)); } echo $buf; } else { foreach ($files as $f) { if (!is_dir($f) or !is_writable($f)) { fwrite(STDERR, "Can't write to $f (or it's not a file)\n"); continue; } $buf = ''; foreach (file($f) as $l) { $buf .= $func($l); } file_put_contents($f, $buf); } } ?>

    Hope it helps someone out there.

    Update: I've had some people ask me why I'm reinventing the wheel. I did cover this above—I have plenty of existing PHP code snippets, and almost no perl. I also am very comfortable in PHP, but it's been years since I've been comfortable in perl.

    Here's an example of something I hacked up, today. I can (relatively) easily turn this:

    dmesg | tail -n5

    ... which returns this:

    [17214721.004000] sdc: assuming drive cache: write through [17214721.004000] sdc: sdc1 [17214721.024000] sd 7:0:0:0: Attached scsi disk sdc [17214721.024000] sd 7:0:0:0: Attached scsi generic sg1 type 0 [17214722.464000] FAT: utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive!

    (the first field is the time since boot... useless for my feeble human brain)

    into:

    dmesg | ./pie.php 'static $prev = false; static $boot = false; if (!$boot) { list($boot) = explode(" ", file_get_contents("/proc/uptime")); $boot = time() - (int) $boot;} if (!$_) return; list($ts, $log) = explode(" ", $_, 2); $ts = str_replace(array("[","]"), array("",""), $ts); $_ = date("H:i:s", $boot + $ts); if ($prev && ($diff = round($boot + $ts - $prev, 2))) $_ .= " (+". $diff .")"; $_ .= " ".$log; $prev = $boot + $ts;' | tail -n 5

    (line breaks added for easier reading)... which returns:

    17:07:44 sdc: assuming drive cache: write through 17:07:44 sdc: sdc1 17:07:44 (+0.02) sd 7:0:0:0: Attached scsi disk sdc 17:07:44 sd 7:0:0:0: Attached scsi generic sg1 type 0 17:07:45 (+1.44) FAT: utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive!

    That's the sort of thing I wouldn't be comfortable doing in perl, but I hacked up on the command line in PHP.

  3. Slides for PHP Phone Home

    In the put-your-slides-online-after-your-talk tradition, here are mine: http://www.phpdoc.info/talks/php_phone_home-vancouver.pdf. Enjoy. Or don't. (-:

  4. Merry Christmas!

    I'm currently in the middle of backwoods-nowhere. There's no wired broadband of any sort, here, so I'm using my wife's parents' satellite internet, which is pretty good from a raw bandwidth standpoint, but really bad on the latency front. Ping times to our phone server are in the 600ms+ range (normally, this is 30ms).. so, anything that requires any sort of realtime interaction is hardly usable.

    Here's their place. The roads don't even have names, according to my GPS software.

    Anyway, I just wanted to drop a note wishing the community a Merry Christmas--and happy 2007!

  5. Stuck on a bus in Redmond

    So, I know I haven't blogged in a long time, but I couldn't pass this one up.

    A bunch of us are in Redmond at the Microsoft Developer Summit. Mostly PHP guys. A few core guys, even. Anyway, it ended a couple hours ago, and after a quick stop at the MS Company Store (where I picked up a cheap copy of MapPoint + GPS locator), our bus was hit by a car, and a bunch of us are stuck on it, in the middle of the freeway, waiting for the police to show up.

    Fortunately, I'm able to piggyback on someone's WIFI. Thanks myhome.westell.com!

    Anyway, as I mentioned, I just got a new GPS. Here's where we are:

    I've got 1:30 left on my battery. Hopefully we'll be back to the hotel by then. (-;

  6. MySpace: Welcome to Web 0.5 (and a Y!Maps toy)

    I'm not much into social networking sites. I joined the big wave of PHPers on LinkedIn, but I haven't really used it. Some of my friends/clients, however, are really into MySpace.

    Sunny (my aforementioned friend), uses MySpace to promote his band. He maintains his upcoming tour dates within his MySpace profile. I maintain the code behind his site (he maintains the content), and I thought it would be a nice feature if he could update his tour dates in a single place, and have them syndicated elsewhere.

    Since (as far as I can tell) there's no real API to update MySpace, the only viable way to achieve a central datastore is to read from MySpace. "No problem," I thought, "I'll just write up a quick wrapper for whatever format they use for Upcoming Show syndication."

    (Read on to see the Flash app I came up with as a result of this whole adventure.)

    Turns out, there's no API for that, either.

    Great. What is this? 2002? "On to Plan B." Plan B involves page scraping. Remember that? It's that thing we did back in the olden days, before RSS caught on. It involves some sort of network layer to grab the content (PHP's streams to the rescue, here), and usually a huge regular expression or three. Where's the Semantic Web when we need it? (side note: notice the "2001" in that URL? Yeah.)

    I'm going to let that (side note) distraction lead me on another tangent: What's with MySpace, anyway? It's the new Geocities. It's got the be the biggest mess on the Web (but not the Internet as a whole--that title is reserved for the current state of email). All that it's missing is blinking text, "under construction" logos, background music, animated word-art, impossible-to-read-text-on-background-images, and HUGE FONTS. Oh wait, no.. it's not missing any of that.

    Note also that MySpace is not only behind on tech when it comes to new-Web things like RSS, but if you've ever had the.. uh.. pleasure of looking at MySpace's HTML source (and you didn't immediately pluck out your eyeballs), you'll agree with me that the markup is reminiscent of mid-90s-era HTML 3.0.

    MySpace: I declare you Web 0.5 compliant. Congrats! (Well, I guess retro is in... right?)

    So, (back on topic) I whipped something up to fake syndication. If your band happens to have a MySpace profile, and you maintain your tour dates on MySpace, first accept my apologies for that, then take a look at: http://www.caedmon.net/msm/rss.php?fid=brandnew (where brandnew is your myspace friendid (name or number)).

    It's certainly not foolproof, but it allows for cool things like this Live Map: http://www.caedmon.net/msm/map.php?fid=brandnew.

    Anway, the RSS allowed me to integrate Sunny's tour dates into his site (if you look closely, you'll see the foolish parts that are not um.. proofed). Mission accomplished.

    But that map thing is really cool. I wanted him to be able to integrate a live version of the map into his profile page.

    Fortunately, Yahoo! has cool developer tools, including for Y!Maps. (Rasmus blogged about these, a while back.)

    MySpace, by their very nature, has had to lock down their profile pages, somewhat. This means: no JavaScript, no IFrames (because of XSS, CSRF, and the potential for worms). Some creative users have, however, figured out how to bypass some of their safeguards (see this -- typical MySpace warnings apply (it plays music)).

    So, a big no-go on putting the map into an IFrame. Time to dust off Flash (and download a fresh 30-day trial! (-; ). MySpace allows embedding... but adds attributes to the tag so Flash can't script page elements.

    A few hours later, I managed to concoct the 60-or-so lines of ActionScript (Flash's scripting language) required to pull off a Flash version. (I first tried to overlay my RSS, but something was mysteriously broken.)

    Voila:

    Check the source of this post for embedding details. The URL is: http://www.caedmon.net/msm/flash/msm.swf?brandnew (again, brandnew is the MySpace FriendID).

    Enjoy. If you use any of this stuff, let me know.

    Oh, and to MySpace: shame on you; update thyself!

  7. You can, but you shouldn't

    "Here's the mascot," he said, leaning over one of my two half-walls, handing me a file of papers, "the production guys will get you the artwork. The jokes are at the back. Call me when it's ready."

    It's early 2000. I'm slaving away in my pseudo-cube in my hometown. I'm a script monkey. My job consists of writing minimal CFML (oh yeah, Coldfusion, baby) wrappers around boring products, like fish hooks.

    Denis, the cube-leaning account manager, had tasked me with a project that was mostly impossible (at the time), but moreover, it was a project that simply shouldn't have been done.

    The pitch was delivered earlier in the day. "It'll be great! The user will be browsing the website, and the dog (the dalmation mascot) will walk onto the screen and tell a joke!"

    Now, remember, this is 2000--at the end of the first browser war; the peak of browser non-compliance; a time when developers were using IE as their primary browser and cringed when forced to test code in Netscape (v4) (as opposed to today, when many developers are using a Mozilla-based browser (Netscape's evolved grandson) and are disgusted by the thought of testing on IE).

    Technically speaking, we probably could have rigged up a solution that might have worked on most IE installs, but this gave us a convenient excuse to overthrow the marketing fools: the idea was horrible. Our answer was that there was no technology that would allow us to implement the absurd joke-telling-mascot idea.

    Sometimes you can, but you shouldn't. This proverb leads nicely into one of my latest web annoyances.

    Like any good technically-minded person, I hold more than the average share of pet peeves. Many are related to software, many more to computing in general. A few are directly related to my area of expertise: the Web.

    So, I ask you, my fellow Web developers: WHY do you find it necessary to create your own widgets, when there's a good (albeit limited) toolkit available? Stop it. It drives me crazy.

    Want examples? Here you go:

    saq.com zoomerang.com digg.com

    Admittedly, the stock HTML widgets might not be as pretty as these custom ones, but they WORK, they're consistent from site-to-site, and you don't have to worry about javascript bugs.

    For example, on the select boxes, above (digg.com and saq.com), I can't click the box and press the first letter of my suggestion (like I can with real HTML select boxes). The radio buttons don't honour keyboard input, either -- I can't use the arrow keys to advance. Generally, these hacked-together widgets don't respect the tab key, either.

    And if you're using a text based browser (for whatever reason), or perhaps screen reading software, you're pretty much out of luck.

    You wouldn't draw each pixel in a line of text would you? Of course not! (unless you're this guy).

    In short: your pretty site is no nicer than the joke telling dalmation. Cut it out.

  8. Wikipedia (English) Hits 1,000,000 articles

    Today, at around 18:10 EST, I noticed that the English version of wikipedia had just crossed over into the 1,000,000 qualified article realm.

    Kudos, Wikipedians (and PHP users).

    Update: preliminary guess which article is #1 Million (it's hard to calculate because not all articles qualify, and deletions are hard to track): http://en.wikipedia.org/wiki/Aaron_Ledesma.

  9. re: Secure Logins (fun with Greasemonkey)

    Chris posted about Secure Logins, last week. In it, he describes the confusion that exists when users cross from HTTP to HTTPS via forms.

    Chris isn't alone in noticing this problem. A few weeks ago, on the Security Now! podcast, Steve Gibson answered a user question about the same problem.

    On Chris' blog, I mentioned that this would be a good use for Greasemonkey. (If you don't know about Greasemonkey, you should definitely check it out.)

    Since then, I've had two flights, and took a little time to work out a solution to the problem.

    When hovering a form button, image or submit input, you'll see a description of the form's action, and various potential problems (onsubmit, onclick, etc).

    It doesn't solve all "hijacking" problems, but it's not supposed to.. it's just a quick indicator of where your form probably posts.

    Even if you're not interested, take a look at the source for a cool little embedded image trick.

    Enjoy.

  10. To All:

    But especially Chris:

    [php] 'mass', // http://en.wikipedia.org/wiki/Newton%27s_laws_of_motion#Newton.27s_second_law:_fundamental_law_of_dynamics '783487' => 'y', // arbitrary number 's' => 'preg_replace', // perl )-: 2.71828 => 'e', // http://en.wikipedia.org/wiki/E_%28mathematical_constant%29 'x' => '278127', // arbitrary number '278127' =>'Christ', // http://en.wikipedia.org/wiki/%CE%A7 'y' => '783487', ); $formula = array( 'M', 2.71828, 'r', /* pow(r, 2) */ 'r', /* = r*r = rr */ ( pow((1/$constants['y']), -1) ), "\n", sqrt(pow($constants['x'], 2)), $constants['F/a'], // force = F; acceleration = a "\n", 's/ss/s' ); $adjust = array_pop($formula); $message = ''; foreach ($formula AS $p) { if (isset($constants[$p])) { $message .= $constants[$p]; } else { $message .= $p; } } list($func, $regex, $replace) = explode('/', $adjust); $message = call_user_func($constants[$func],"/{$regex}/","{$replace}", $message); echo $message; ?> [/php]