Status update

Earlier today I switched the site off Tumblr and to my own server, hosted by Linode. So if you can see this, that’s a good sign! If you’re reading the RSS feed you might see some duplicate entries but that should settle down.

It’s now being served as a bunch of static HTML files created with a Python site generator I wrote. It’s not going to replace any of the established ones for anybody, but it was interesting to write and is fairly easy to understand. I’ll write about it when I’ve cleaned up the project.

The site isn’t missing anything, so it’s done in that regard, but there’s still some things left over on my end. For a start, a BBEdit preview template and a makefile to automate the last bits.

Re: Unresponsive

Dr Drang posted recently about his trouble getting his site to work with the new responsive design mode in Safari 9 (which is very similar to the Firefox feature of the same name). He also detailed the complicated setup he has for providing his current mobile layout to small, portrait screens (ie phones) — media queries in HTML link tags and separate stylesheet files.

(I should also point out, if Dr Drang is reading, that his mobile.css file is missing the rule for #content iframe. I’m not sure if this is deliberate.)

Since I’ve fought with responsive design a couple of times, and seemingly have a need to stick my nose into other people’s business, I wondered how difficult it would be to combine the two separate CSS files and get responsive design mode to work.

To give some context to what’s discussed, I’ve put up a gist containing the combined CSS file and required HTML changes. In the CSS file you’ll want to look at the end part, from line 809. That part contains two media queries, which split out:

  1. Rules only for small portrait screens (ie phones).
  2. Rules for everyone else (but not small portrait screens).

The two diffs at the top show the changes from Dr Drang’s mobile.css and style.css. The combined file is based on the main stylesheet, which is why there are more changes in the mobile diff.

Most of the changes that make up the Doc’s mobile style sheet are font-size declarations to boost the text size — and these don’t appear in the combined file, which points to the most interesting aspect of this and something that had me confused for not a short while.

Basically, Dr Drang’s mobile style sheet increases the text size to compensate for the mobile browser rendering at “full size” (980px in Safari on iOS). (This is how the New York Times website looked normal in the first iPhone demo in 2007.) The usual technique is to tell the browser to render at “device size” through the use of a meta HTML tag:

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

It took me a while to work out that this combined with Dr Drang’s larger text to make everything appear massive:

My CSS changes to the And Now It's All This mobile css file caused the text to become huge.

So those rules went, and some new ones to fix the size of the header came in. But otherwise there are no changes to the styles.

The change in approach means that the result isn’t an exact match for the real site:

A portrait comparison of my CSS changes to the real And Now It's All This site.

And in landscape the fixed sizes in the CSS file combine with the use of “device size” to produce a layout that’s larger than the screen width, forcing Safari to resize the viewport until it just fits:

A landscape comparison of my CSS changes to the real And Now It's All This site.

The changes mean that responsive design mode in Safari works for portrait mode:

My CSS changes to And Now It's All This in Safari's responsive design mode in portrait.

But landscape mode is not accurate, as there isn’t the viewport-resizing that squeezes the too-large layout to fit on the phone itself:

My CSS changes to And Now It's All This in Safari's responsive design mode in portrait.

Lastly, I’m going to close with my tips for not going completely mad when trying to make a responsive layout:

  • Have the main part of the CSS file — before any media queries — produce a usable single-column layout (ie for phones).
  • Try to have media queries build on previous rules instead of trying to undo them.
  • Use as few media queries, and as few rules within them, as possible.

I’ve recently rewritten this site’s CSS to prepare for a behind-the-scenes change. Compared to the current stylesheet, first written in 2013, it’s much saner — specifically with regards to media queries but also in general.

Here’s the current stylesheet and the new one if you want to take a look. In the new file the main part, before any media queries, creates a small layout, which is finessed by a mid-sized media query, then finally adjusted for larger screens.

Cameron & Ashcroft

Today’s allegations in the Mail are completely tedious in almost all aspects yet are interesting in one.

Frankly if you’ve gone this long thinking that David Cameron had any shred of humanity there’s no helping you. The 2010–15 Con-Dem coalition was plenty vicious and immediately after winning a majority in May the first thing the Tories did was to screw over deaf and blind people starting work. The day after the vote. These people have no shame and are solely concerned with the interests of their class.

Which is what makes this interesting. Billionaire tax-dodger Michael Ashcroft, the Tories’ former top donor, and the class-warriors at the Mail know full well that their interests are best served by a Tory government. Ashcroft may well feel snubbed at not getting a cabinet job but with £1 billion in the bank there’s plenty he could to do keep himself occupied.

I think this attack on Cameron is meant to make his replacement as Tory leader more palatable. None of the top Tories seem human and they must know it. Boris “three jobs” Johnson, for instance, is known to have been a member of the Bullingdon Club and has admitted taking drugs. (He’s also quite a vicious rightwinger with a tendency to get nasty when challenged, but let’s stick to perceptions.) By painting Cameron as a complete degenerate — a drug-addled ultra-posh pervert who hates ordinary folk — suddenly Johnson (or whichever pretender) seems a lot more acceptable.

Ashcroft’s co-author Isabel Oakeshott made clear to the BBC that publishing the book after the election was done to protect the party. Again: this tax-dodging billionaire knows exactly who his mates are and wants them to stay in charge. It’s just that Cameron’s through and the Tories are suddenly faced with a Labour Party led by a decent human being with decent policies.

Bumping off Cameron and replacing him with someone who’s not seen to be a disgusting pervert who despises the working class (the bigger challenge) is — along with the continuing barrage of media lies against Jeremy Corbyn — the only way to challenge that.

Python’s Counter class, again

I made a mistake in my recent post about Python’s Counter class by using numbers in the example rather than strings. It meant it wasn’t clear what I actually wanted out of the counter. (While I was writing it, I was getting confused between the keys and their counts myself. I should have taken the hint.) That post’s now been updated.

I had a lovely email from Jacob Söndergaard that prompted me into clarifying things, and also started me thinking about ways you can still use max on the counter to get the most common item. Here’s what I’ve got:

from collections import Counter
c = Counter('abracadabra')
most_common = max(c.items(), key=lambda t: t[1])[0]

Here max gets a sequence of tuples (key, count) from c.items() and the custom key function tells it to choose the greatest element based on the count. The [0] index at the end ensures you just get the key, not the count.

But should you do this? No. Please don’t. At this point you’re effectively duplicating the way that Counter implements .most_common() internally. (Here’s the Python source for the method.) That’s at best too — the implementation does something more complicated if you only want the top n most-common elements.

Also: Abracadabra.

Python Counter gotcha with max

Update 2015-08-10

The example given now uses strings as the keys instead of numbers to ward off any confusion between the keys and their counts.

Getting the greatest element from a sequence in Python is dead simple: just use the built-in max function.

Storing the frequency of items is also dead easy with collections.Counter:

>>> from collections import Counter
>>> c = Counter('abracadabra')
>>> print(c)
Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})

The greatest item in a counter is obviously the most common, so surely we’ll just …

>>> max(c)

What? Here’s the gotcha: Python counters are a dictionary subclass. Call max with a dictionary and it’ll get the greatest key, because keys are what you get when you iterate over a dictionary. Same deal.

To get the most common element you have to use — surprise! — Counter.most_common(). Without arguments this produces a list of tuples (item, count), sorted by count:

>>> c.most_common()
[('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)]

So to get the actual most common element, you do:

>>> c.most_common(1)[0][0]

Where the argument 1 limits it to the first tuple.

But what if the counter’s empty? You’ll get an IndexError trying to index into the list returned by most_common():

>>> d = Counter()
>>> d.most_common()
>>> d.most_common()[0][0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

In Python 3.4 max got the default argument, which you can use to get a default value when a sequence is empty. Here’s how to get similar behaviour with Counter:

d.most_common(1)[0][0] if d else None

This takes advantage of the "falsey" nature of an empty dictionary to give you None without having to handle an IndexError.