bluefeet

LinkedIn | GitHub | Twitter

Fixing Pixelated Images on the iPhone

When an iPhone with a retina display (iPhone 4+) displays an image on a web page that image’s size is doubled, so each pixel in the image actually takes up 4 pixels and looks pixelated. This looks unprofessional and tacky. Here’s an example of a 245x80 image:

You’ll have to load this page on an iPhone to see the problem in the above image. The pixels in the image have jagged edges and the photo overall looks blurry.

To get around this all you need to do is double your image size and explicitly set the image size in the <img ...> tag to its original non-doubled size. So, in our example the image is now 490x160, but we set the img tag as <img src="..." width="245" height="80">. Here’s what it now looks like with the image stored at double resolution:

Now it looks crisp on the iPhone.

Adding Responsive Design to Tumblr Themes

If you’re using a single-column fluid layout theme in Tumblr then adding responsive design is dead-easy. If you’re using a more complex theme, that is not fluid width and single-column, then you’ll have to put a lot more work in, but it is still well worth the effort.

By default Tumblr overrides your theme with a mobile-friendly theme when your blog is accessed by a phone. Here’s what my site looks like when Tumblr does this:

The override theme is incredibly basic and provides no extra functionality. You loose your custom design that sets you apart, you loose Disqus comments, etc.

The first step then is to disable Tumblr’s override mobile theme. To do this, go in to the “Customize appearance” tool for your theme. Once open, scroll down in the left-hand pane and open the “Advanced” section. Under here there is a checkbox titled “Use optimized mobile layout”. Uncheck this and click save at the top. Now your theme will always be used. Load up your site on your phone and have a look. Here’s mine at this step:

At this point this appears to be a step backwards - you’ve now made your site less usable. In order for people to use your site now they have to zoom in and scroll left to right for each line they want to read. If we left our site in this state it would be a miserable fail. You can fix this by adding this line just before the <head> tag in your theme’s HTML:

<meta name="viewport"
    content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">

This “viewport” meta tag is telling the browser to not zoom out. By default mobile browsers zoom out enough so that the site can have a display width comparable to a desktop. For fixed-width sites there is no better solution, but for fluid width sites (or sites that only have a max-width, but not a min-width) disabling this auto-zoom provides a much better experience.

So, with this meta tag added, the site now looks like this:

Now the site looks very close to Tumblr’s mobile override theme, but with all your customizations and custom design enabled. Not bad! There are still some issues, such as the body padding being too thick at this resolution. But, overral this is a great step forward.

Now we can make a few more adjustments by using CSS3 media queries. Media queries allow us to craft CSS that is applied only in certain situations. In this case we want the padding around the body to be reduced if the width of the site is below a certain level. Adding this line to the CSS does just that:

@media screen and (max-width: 480px) {
    body { padding: 5px; }
}

Now, when accessed with a browser that reports a width of 480px or less (which in my testing is iPhone in both portrait and landscape mode) then the site looks like this:

Much better! Now when the site is accessed by a phone, the padding is reduced from 30px to 5px and we take better advantage of our screen real-estate.

Now you should have the tools to take your own Tumblr blog to the next level and make it friendlier for your visitors.

Adding Syntax Highlighting to Tumblr Posts

I’ve just moved my blog to Tumblr. One thing that most my posts have are code examples. Here’s how I added this to my Tumblr blog. Go in to the customization section of your blog where you can configure the theme. Once there, click the “Edit HTML” button and add this somewhere before the ending </head> tag:

<link rel="stylesheet" href="http://yandex.st/highlightjs/6.1/styles/solarized_light.min.css">
<script src="http://yandex.st/highlightjs/6.1/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

Adjust “solarized_light.min.css” to point to whatever highlight.js theme you’d like to use. The themes can be viewed on the highlight.js test page.

The only problem I’ve run in to is with tumblr’s infinite scrolling feature. Since highlight.js is applying syntax highlighting when the page first loads then any code blocks that are loaded as you scroll will not get highlighted. I’m sure there is a way around this, but for now I just disabled this feature in my blog’s preferences.

Check out SQL::Abstract::Query

During the last few months I’ve been working on the CPAN distribution SQL::Abstract::Query. The drive for doing this is that DBIx::ResultSet (another module of mine) currently has lack-luster support for auto-incrementing IDs, has a custom and inflexible solution for GROUP BY, and has no support for JOINs.

To solve the first problem, with lack of good auto-incrementing ID support I wanted to make a generic module that would allow anyone to retrieve these IDs and could be used independently from DBIx::ResultSet. So, I set out to build DBIx::AutoID. I quickly found that there is a huge myriad of complexities to do this right for all the different databases out there. In the end I came to the conclusion that I need some way for an INSERT to be represented as an object so that DBIx::AutoID can modify it, if it needs to, before it is executed so that the ID may be returned.

The second two issues, bad support for GROUP BY and none for JOINS, really just required extending SQL::Abstract and overriding its behavior.

So, take a look at SQL::Abstract::Query on CPAN and let me know what you think. I’d really like to get some feedback. There is a large list of TODOs, but I’m confident that the interface as it is now won’t change much, just the internal guts need some work here and there.

Expect DBIx::AutoID (with inspiration from DBIx::Class) to be on CPAN in a few weeks as well. Then, I’ll get around to updating DBIx::ResultSet with all these new and more powerful features.

PS: The current development work is being done on the SQL-Abstract-Query github repository.

Using DBI Effectively: bind_columns()

One of the most under-utilized features of DBI is is the bind_columns() method. The majority (as in everyone) that I show bind_columns() to have never seen it before or used it. Here’s what it looks like:

my $sth = $dbh->prepare('SELECT name, email FROM users');
$sth->execute();
$sth->bind_columns( \my( $name, $email ) );

while ($sth->fetch()) {
    print "$name: $email\n";
}

bind_columns() takes a list of scalar references as its arguments. The form you see above with \my(…) is just a little known Perl-ism shortcut for:

my ($name, $email);
$sth->bind_columns( \$name, \$email );

There are two important reasons why bind_columns() is so awesome:

First, it greatly reduces the complexity of the code within the while() loop since you do not have to lookup in to an array ($sth->fetchrow_array()), de-reference an array ($sth->fetchrow_array()), or de-reference a hash-ref ($sth->fetchrow_hashref()). Instead the values themselves are available via appropriately named scalars.

Secondly, when using bind_columns() DBI is re-using the same scalars every time a fetch() is done which is much faster than creating an array or hash every fetch and typically causes the values to be copied one less time than normal. Benchmark it yourself - bind_columns() can make a huge difference when processing large sets of data.

Chained Git Hooks

So I’ve be wrestling with getting chained git hooks working. I’m surprised that Git doesn’t support this out-of-the-box as it seems very short-sighted. Here’s a Perl script I implemented to get this working:

#!/usr/bin/env perl
use strict;
use warnings;

use autodie;
use File::Temp qw( tempfile );
use IPC::Cmd qw( run );

if (@ARGV and $ARGV[0] eq 'wrapper') {
    shift( @ARGV );

    my $hook_filename = shift( @ARGV );
    my $temp_filename = shift( @ARGV );

    open( STDIN, '<', $temp_filename );

    exec($hook_filename, @ARGV);
}

my $hook_type = $0;
$hook_type =~ s{^.+/}{};

my $git_dir = $ENV{GIT_DIR} || `git rev-parse --git-dir`;
chomp( $git_dir );
my $hook_dir = $git_dir . "/hooks";

opendir( my $dh, $hook_dir );
my @hooks = sort grep { /^${hook_type}_/ } readdir( $dh );
closedir( $dh );

my ($temp_fh, $temp_filename) = tempfile(UNLINK => 1);
while (my $line = <STDIN>) {
    print $temp_fh $line;
}
close( $temp_fh );

foreach my $hook (@hooks) {
    my ($success, $error) = run( command => [
        $0, 'wrapper',
        "$hook_dir/$hook", $temp_filename,
        @ARGV,
    ]);
    print join('', @$full_buf);

    if (!$success) {
        die "Error running hook: " . $hook . ": $error\n";
    }
}

So, what you do is put this somewhere you can get at (perhaps just drop it in your hooks directory with the name “chained_hook”), chmod 755 it, and then symlink all your hooks to it, for example:

ln -s chained_hook applypatch-msg
ln -s chained_hook commit-msg
ln -s chained_hook post-commit
ln -s chained_hook post-receive
ln -s chained_hook post-update
ln -s chained_hook pre-applypatch
ln -s chained_hook pre-commit
ln -s chained_hook pre-rebase
ln -s chained_hook prepare-commit-msg
ln -s chained_hook update

Each of these chained hooks will now look for sub-hooks with the name “hookname_subhookname”. So, you could add a “post-receive_email” and “post-receive_foo” hooks and both will be called, in sorted order, by the post-receive hook.

So, I’m wondering - do people think this is a good solution? Are there better solutions? Is there a simpler way to write this script?

Adding Files to Subversion With @ in Their Name

I just ran in to this today. If you try to do this:

svn add this\@that
svn: warning: 'this' not found

In order to ‘svn add’ a file with a ‘@’ character in it you must end the add command with an ‘@’ character, as in:

svn add this\@that\@
A          this@that

Presentation: Moose Best Practices

I wrote this for the TO.pm meeting on August 11th, 2010:

Presentation: Tools of the CPAN Ninja

I wrote this for the TO.pm meeting on June 10th, 2010:

BLOBs, Synonyms, and DBD::Oracle

INSERTing, UPDATEing, and SELECTing LOBs (CLOB/BLOB) in Oracle using Perl can be a PITA. Case in point: 2 years ago a fellow coworker ended up writing some extremely complex code using ora_lob_write(), etc, when all he really needed to do was use bind_param() and declare that the blob column is a blob so that DBD::Oracle would know to treat is specially. At the time I believe he did try something like:

my $sth = $dbh->prepare(q[
    INSERT INTO some_table (color, blob_data)
    VALUES (?, ?)
]);
$sth->bind_param( 1, 'red' );
$sth->bind_param( 2, $data_for_blob, {ora_type => ORA_BLOB } );
$sth->execute();

But then an error like “DBD::Oracle::st execute failed: ORA-04043: object some_table does not exist (DBD SUCCESS: OCIDescribeAny(view)/LOB refetch)” was raised. Which made no sense since some_table is very much an object and any number of SQL operations work on it… when BLOBs are not involved. In the end he ended up having to write code that was triple the size to get around this issue.

So, 2 years later and a little hair pulling, I come to figure out by luck that the problem is that the underlying DBD::Oracle code, that makes dealing with BLOBs simple, fails when you are using a synonym in your insert. All we had to do is fully spell out the table name, and it works!

my $sth = $dbh->prepare(q[
    INSERT INTO some_schema.some_table (color, blob_data)
    VALUES (?, ?)
]);
$sth->bind_param( 1, 'red' );
$sth->bind_param( 2, $data_for_blob, {ora_type => ORA_BLOB } );
$sth->execute();