Prevent Browser Caching

You can’t force a browser (or other User Agent) to do anything. You must carefully implement your server side code to prevent malicious or accidental damage. That said, you can sometimes improve the user experience a lot by asking browsers nicely not to cache anything and thus to request the page again when (amongst other things) the Back button is used.

You can do this with the following HTTP headers. (Note: This doesn’t work on Opera as it does on other browsers.)

Cache-Control: no-cache
Cache-Control: no-store
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache

In PHP you can do this with:

header("Cache-Control: no-cache");  // Forces caches to obtain a new copy of the page from the origin server
header("Cache-Control: no-store");  // Directs caches not to store the page under any circumstance
header("Expires: " . date('D, d M Y H:i:s', 0) . ' GMT'); //Causes the proxy cache to see the page as "stale"
header("Pragma: no-cache");         // HTTP 1.0 backward compatibility

This is not the perfect solution. If the browser ignores these headers (as Opera will – see comments) then you can still go back and see stale pages. I wonder what banks do to get around this where the viewing of a stale page can be considered a security breach?

Combinatorics in Ruby

Some simple additions to Integer for combinatorics purposes. Will calculate the number of possibilities in an “n choose m” scenario (no repetitions). Adds factorial because that is required for the calculation.

Usage:

irb(main):001:0> require 'combinatorics'
=> true
irb(main):002:0> 3.fact
=> 6
irb(main):003:0> 10.fact
=> 3628800
irb(main):004:0> 100.fact
=> 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
irb(main):005:0> 3.choose(2)
=> 3
irb(main):006:0> 6.choose(2)
=> 15
irb(main):007:0> 100.choose(7)
=> 16007560800
irb(main):008:0> 10000.choose(27)
=> 88666586562493644592361321224866562980818106140387273533229708768701222758880000

Code:

class Integer
  def choose(m)
    return (self.fact / (m.fact * (self - m).fact))
  end

  def fact
    (2..self).inject(1) { |f, n| f * n }
  end
end

Science in Virtual Worlds

I attended the Science in Virtual Worlds event at the London Apple store yesterday evening. I’ve always been quite cynical about systems like Second Life but I am having second thoughts now.

SciLands is an interesting place. The National Physical Laboratory and NASA (amongst others) have created an area dedicated to hard science and science education.

Dave Taylor of the NPL made a spirited case for the usefulness of Second Life. In addition to bringing geographically divided people together (much like email or instant messaging can) he argued that the use of a three-dimensional world had extra advantages.

It increases the sociability of situations (with real world cues such as stepping towards the centre to speak to a group arranged in a circle). This makes the interactions richer and more “real” than something like email. It also encourages informal conversations. For example, after a video conference the camera is switched off but after a Second Life conference, avatars must move away or can form smaller groups, renew acquaintances and so on as in a real conference. Serendipity is also increased by allowing anyone anywhere on the globe to be neighbours. One of NPL’s areas borders the University of Denver and they are now engaged on a joint project to bring a nuclear power station to Second Life, something that would not have happened were they not neighbours.