January 10, 2007

Input fields that resize themselves?

With multiline input fields text is word-wrapped and a vertical scrollbar appears if the allotted space is not enough, but when you outgrow the width of a single-line text input no horizontal scrollbar appears to help you out - at least, not in any browser I’m familiar with. Does that seem right to you?

I suggest something like this:

December 31, 2006

Overcoming Coder’s Block

For my entire programming career (that is to say, my whole life), I’ve been searching for a solution to what I call “Coder’s block”. Roughly half of the days I sit down in front of my editor I find that I simply can’t get started. I’d imagine anyone who has been coding for longer than a week will agree that the most difficult problem is often simply finding out where you (or the guy before you) left off yesterday, last month, last year, or before you took out the garbage. Once you know where to start, the how falls into place by itself.

I can only speak for myself, but during this reacquaintance stage I’ll often get distracted by just about anything. Usually the culprit is Bloglines, Thunderbird, Gaim, or any other application that pops up to notify me of something going on. Giving into these temptations is suicide. I can literally get sucked in and spend an entire day accomplishing absolutely nothing.

Writer’s block is easy by comparison - simple techniques like freewriting and mindmapping can help to keep you focused and free of distraction. But what techniques can be of use when writing software?

What works for me:

  • Create a work environment with as much artificial light and as little clutter as possible. I don’t know why, but sunlight is actually more laziness-inducing than darkness for me - I keep the blinds closed. Unfortunately I’m a bit of an ogre by nature so often removing said clutter could be as much of a day-long distraction as anything else.
  • Go full-screen and kill any processes that intrude by popping up. Setting the taskbar to auto-hide (if you use Windows) may also be helpful.
  • Take a few minutes to read a relevant article or book passage - there’s very little more motivating than discovering a new technique, but make sure it’s one that can be put to use in the project at hand. It’s far too easy to end up with a thousand unfinished sideprojects if the technique requires starting something new to try it out. It may be beneficial to set a timer if you’re at risk of getting sucked in.
  • Avoid social news websites (such as digg) at all cost.
  • If you’re the kind of guy who always seems to have a thousand browser tabs open, try using the session manager in Tab Mix Plus to keep unrelated tabs out of sight and mind while you’re working. I like to have a separate saved session for each project I’m working on, and another for when I’m taking a break that has tabs like Bloglines and Slashdot.
  • If you’re the type to listen to music at work, make sure it isn’t going to be a distraction. Upbeat tunes without lyrics work best for me. If you find you are frequently interrupting yourself to change tracks, remove control by tuning into streaming radio instead.
  • Invest in a machine with enough RAM to keep all your work applications running simultaneously. A lot of the time all it takes to break my concentration is the 30 seconds to launch a program. This will pay for itself many times over in increased productivity.
  • As a last resort, reboot your day. This is something I do not just with work, but any time a day is going so incredibly badly it just can’t be saved. Turn off the lights and take a quick nap. 20 minutes is best. When you get up, take a shower, make a small breakfast, and just go through your morning routine as if it were the first time. Try to forget anything prior even happened.

What doesn’t:

  • When you’re having trouble getting started, it’s easy to tell yourself that all you need is a 5 minute break - this is probably not true. Try to save all the little break-time chores (phone calls, making a fresh pot of coffee…) for later, and knock them out all at once. If you’re at risk of forgetting them, try making a list. Once I get rolling breaks are fine, in fact I often need to give myself a couple minutes away from the keyboard to let my mind catch up.
  • Avoid TV, podcasts, and games. Hopefully this one is obvious, but so many people try to ignore it anyway.
  • Don’t let other people intrude. Put the phone on silent, lock the door - whatever it takes. You can get back to them later. Just a 60 second distraction can cost a programmer 15 minutes. Only programmers and writers seem to understand this concept.

What works for you? For the love of god please add anything you find helpful to the list.

15 minutes left….. 2007 here we come!

December 21, 2006

Firefox search plugin - Mininova ordered by seeds

When there are a lot of resulting torrents for a search on mininova I always end up resorting them by seeds to force the best results to the top (hurray for the accidental power of the social web!), so I modified the existing mininova search plugin to save myself a step.
Click here to download - or don’t, I really couldn’t care less!

 Installation: Save the file to Mozilla’s “searchplugins” directory (either in the shared application directory or inside your profile), and restart your browser. All done :)

December 17, 2006

You got PHP in my CSS! You got CSS in my PHP!

While a purist might keep faithfully hitting the refresh button on all the major browsers, tweaking his CSS until he turns #1f5acf in the face (or his startup budget runs out, whichever comes first), your time is worth more than that. A quick-and-easy solution for the rest of us is to serve up a different set of styles depending on the user agent. Many thanks to Gary White for his excellent browser-detection class.

I know this site has some nasty rendering bugs in Opera and IE6 (maybe Safari also, I haven’t tested it yet). Now that I’ve got the power of phpStyles on my side, I’ll see about getting those taken care of this week.

December 15, 2006

Fishy Eyes for Web UIs

The other night my trusty feedreader alerted me to a Nitobi post demonstrating a fisheye menu (think Mac OS X dock) in javascript as a part of their upcoming library. A neat effect, to be sure…and useful as well; menu design is so often reduced to a balancing act between the number of items displayed and the actual visibility of each. I fully expect this type of widget to become much more common on the web as the major js animation toolkits begin to offer it.

Searching for a way to do this with script.aculo.us or moo.fx yielded no result, but I did come across another interesting (slightly lesser-known) toolkit - Dojo. I played with it for a few hours and loved it’s functionality, but decided to abandon it for philosophical reasons. I may see about implementing the fisheye widget in script.aculo.us if I ever have time…sooner or later someone has got to.

The above example pulls images from the Flickr API based on the tag you search for, sorted by interestingness. If you want to play around with the code on your own server, you need Dojo and phpFlickr in the same directory as the script. You can get a Flickr API key here. Enjoy!

December 13, 2006

Does this look like a half-finished Wordpress template to you?

Well, that’s because it is. It’s been a long time since my last post, and a lot has changed. So let’s just get the important stuff out of the way, shall we? In order of importance (start scanning when personal relevance begins to dwindle)…

  • I’ve jumped ship to the Wordpress publishing system, which is infinitely better than Movable Type.
  • My dog ate The old database died in a horrific accident (Yeah, it was my fault), and I had to copy->paste each of the old posts into the new system by hand. I may have made some mistakes here or there. Also you’ll notice all your valuable comments are gone… it was just too much manual labor for one day. I’m very sorry.
  • The blog has a name. This opens it up to the possibility of multiple authors (someday). In case you’re wondering why Skin Deep, ultimately my focus is on the subject of beauty, be it a classy python hack, a stunning Wordpress skin (ha!) or simply a way of looking at insipid day-to-day life that paints it in a more colourful way.
  • Feeds are now managed by Feedburner. If you were subscribed to the old feed, you may need to resubscribe. If you weren’t subscribed at all, you don’t know what you’re missing! Maybe you should consider it.
  • Permanence is relative, at least when it comes to weblog permalinks. When I get around to it (I promise I will!) I’ll get redirects set up for all the old links.

All that boring nonsense aside, it’s safe to consider this blog back with a vengeance, and hopefully you will over the course of the next few posts. Now look, a cute ferret.

Lap Ferreeete

October 18, 2006

Symfony files prefixed by .tmp when installing from PEAR?

Update: I eventually solved the problem by setting my PHP memory limit to 32m and reinstalling via PEAR. The first attempt (at 8mb) had run out of memory and crashed, leaving me with a broken copy.

I experienced a weird issue today when installing the symfony framework for PHP. I used the PEAR install method, and everything went smoothly until I tried to run the symfony command from my shell. It turns out a few hundred very important Symfony files were prefixed “.tmp” for some reason that I’ve been unable to ascertain. Anyway, after renaming these files, Symfony worked like a charm.

If you found this page through Google because you’re having the same issue, you can download and run this simple script I wrote for a quick and easy solution. But be sure to read the warning at the top ;)

Cheers.

October 16, 2006

AJAX with Smarty? It can be done!

Under normal circumstances, once you’ve passed your footer template to Smarty->display(), you’re done. There’s no going back without a refresh. Well, that was before Dmytro Shteflyuk wrote a sexy PHP library, aptly named smarty_ajax.

It does have some limitations, however; one of which is a complete lack of support for object-oriented PHP. I modified smarty_ajax’s ajax_update and ajax_call tools and (among other things) added an optional parameter, object=”". Now you can call class methods from the client with just one line of code, and display their output, all without giving up Smarty as your templating engine!

Since I haven’t yet had a chance to contact Mr. Shteflyuk about committing my patch, you can stare at, download, play with and mangle my version from here for the mean time. But if you break something, don’t expect him to know anything about it! Comment here or email me for help instead, until it is released.

peace

September 30, 2006

Caching for PHP5 and libcurl

Some day you may find yourself in a situation where repeatedly accessing a remote file with libcurl is too slow and resource-wasteful, but the remote file may be different in an hour so you can’t rely on a local copy to be up to date. When that day comes, this snippet should do the trick.

Note that the $cache_dir must be writable by PHP, and that you must be using PHP5 with the libcurl binding (check your phpinfo() output if you’re not sure).

class YourParser{

var $curl; // cURL handle

var $cache_dir = 'cache_dir';

function YourParser() {

// Constructor

// Set up libcurl

$this->curl = curl_init();

curl_setopt($this->curl, CURLOPT_FAILONERROR, 1);

curl_setopt($this->curl, CURLOPT_RETURNTRANSFER,1); // return into a variable

curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, 1); // allow redirects

}

function fetch($url, $cache_life = 0) {

// Fetches a page with libcurl. Cache life measured in seconds. Returns the page content as a string.

// Does not yet support POST form fields.

if ($cache_life <= 0) {

// Caching is disabled.

// Download the page

curl_setopt($this->curl, CURLOPT_URL, $url);

return (curl_exec($this->curl));

} else {

// Caching is enabled.

$cached_fn = $this->cache_dir.’/’.md5($url);

$cached = file_get_contents($cached_fn);

if ($cached === false) {

// Could not open cached version of the file.

curl_setopt($this->curl, CURLOPT_URL, $url);

$results = curl_exec($this->curl);

// Write it to cache and return it

if (file_put_contents($cached_fn, $results) === false) {

// Failed writing to cache. Not writable?

}

return ($results);

} else {

// Cached file retrieved successfully

// test age

$age = time() - filemtime($cached_fn);

if ($age < $cache_life) {

// Cache is still alive

return ($cached);

} else {

// Cache is expired

curl_setopt($this->curl, CURLOPT_URL, $url);

$results = curl_exec($this->curl);

// Write it to cache and return it

if (file_put_contents($cached_fn, $results) === false) {

// Failed writing to cache. Not writable?

}

return ($results);

}

}

}

}

}

September 7, 2006

Creating a Tip-of-the-Day with PHP (and more)

The concept of a tip-of-the-day screen is old hat for many desktop applications, but oft-forgotten by web developers. However, as our web applications grow more complex than ever, we find ourselves in need of better ways to educate our users, introduce new features, and remind them about old ones.

Sure it’s easy enough to code a database-powered tip of the day script, but you don’t have to. Simply bookmark this page, and avoid the hassle.

First things first. Download this library: DidYouKnow 1.0

Aside: My mind was a little foggy when I wrote it, which is probably apparent in the code but it does indeed work. If you make any fixes or enhancements I’d love to include them, so send me an email.

To use this library unmodified, you must have a global ADOdb object in your script called $db (I know, I know…). After installing ADOdb and DidYouKnow on your server, do something like:

require_once('adodb/adodb.inc.php');'

require_once('tip_of_the_day.php');

$db = NewADOConnection('mysql');

$db->Connect($db_server, $db_user, $db_password, $db_name);

$dyk = new Did_You_Know(Name of your table);

Everything we need is in place now, and we can begin creating our custom tip of the day, joke of the hour, or whatever else you’re planning on doing. On that last line, you can input any table name you like so long as it doesn’t already exist - it will be created for you.Adding items to the queue is simple:

// From a string

$dyk->add('Example tip');

// From an array

foreach ($list as $item) {$dyk->add($item);}

// From a CSV file

$list = explode(',', file_get_contents($filename));

foreach ($list as $item) {

$dyk->add(trim($item));

}

Now that you’ve got some data to work with, let’s look at some of the ways you can retrieve it. The table created by DidYouKnow contains a “cursor” column. If you have no need to maintain state, you can safely disregard this, opting to fetch items by their id’s directly. However, choosing to use the cursor affords you some interesting options:

Tip of the Day

display.php

// Display the tip

$dyk = new Did_You_Know("tf_DidYouKnow");

$DidYouKnow = $dyk->fetch();

echo $DidYouKnow->fields[fact];

advance.php

$dyk = new Did_You_Know("tf_DidYouKnow");

$dyk->cursor_advance();

cron (run at midnight every day)

0 0 * * * advance.php

Random tip every pageload

$dyk = new Did_You_Know("tf_DidYouKnow");

$DidYouKnow = $dyk->fetch();

echo $DidYouKnow->fields[fact];

$dyk->cursor_randomize();

I know there are some problems with this incarnation of the DidYouKnow library, but hopefully this will save someone a few hours of painfully boring code, despite the obvious shortcomings. The methods available to you are:

add($fact) Adds an item to the table, where $fact is a string.

remove([$fact_id]) Removes an item from the table. If $fact_id is not supplied it will remove the item containing the cursor and advance the cursor once.

fetch([$fact_id]) Fetches the current item, or an item specified by the optional $fact_id

cursor_advance() Advances the cursor one row

cursor_retreat() Retreats the cursor one row

cursor_randomize() Moves the cursor to a random item

cursor_goto($fact_id) Moves the cursor to an item specified by the required argument $fact_id (even if it does not exist, so be careful)

As always, if you make any useful changes or additions, I’d love to hear from you, so let me know. If you’re looking for direction, I’d suggest creating a seperate table for the cursor so it’s state can be stored once, instead of once per row.

Thanks and good luck!

Inspiration

6pli Tumblr Aptana IDE Markus Homm Mint Humanized Rawkus Records // All Things Hip Hop // www.rawkus.com The New York Times WeShouldDoItAll Justinsomnia Deluxe Digital Media Democracy Internet Tv Take More Photos fluxiom - capture, manage, access and deliver content across your enterprise Olivier Danchin Jason Santa Maria Tubetorial Ajaxian Raincity Studios 88 Miles - Simple time tracking Welcome to Zopa (UK) - The first lending and borrowing exchange Inspirational design for a web2.0 homepage