<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: charles-miller</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/charles-miller.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2009-09-23T15:08:18+00:00</updated><author><name>Simon Willison</name></author><entry><title>Quoting Charles Miller</title><link href="https://simonwillison.net/2009/Sep/23/enterprise/#atom-tag" rel="alternate"/><published>2009-09-23T15:08:18+00:00</published><updated>2009-09-23T15:08:18+00:00</updated><id>https://simonwillison.net/2009/Sep/23/enterprise/#atom-tag</id><summary type="html">
    &lt;blockquote cite="http://fishbowl.pastiche.org/2009/09/23/google_you_clever_bastards/"&gt;&lt;p&gt;Ask browser users, and they'll tell you the overwhelming reason why they can't upgrade to a more modern, standards-compliant browser is because their work won't let them. Ask IT departments why this is the case and they'll point to the six- to seven-figure costs of upgrading turn-of-the-century Intranets written to work in, and only in, Internet Explorer 6. Google have provided a way for websites to opt out of IE6 (and even IE7) support without requiring enterprise-wide, Intranet-breaking browser upgrades.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="http://fishbowl.pastiche.org/2009/09/23/google_you_clever_bastards/"&gt;Charles Miller&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chrome"&gt;chrome&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chromeframe"&gt;chromeframe&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ie6"&gt;ie6&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/internet-explorer"&gt;internet-explorer&lt;/a&gt;&lt;/p&gt;



</summary><category term="charles-miller"/><category term="chrome"/><category term="chromeframe"/><category term="google"/><category term="ie6"/><category term="internet-explorer"/></entry><entry><title>And so it goes, around again</title><link href="https://simonwillison.net/2009/Sep/3/and/#atom-tag" rel="alternate"/><published>2009-09-03T09:46:33+00:00</published><updated>2009-09-03T09:46:33+00:00</updated><id>https://simonwillison.net/2009/Sep/3/and/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://fishbowl.pastiche.org/2009/09/02/and_so_it_goes_around_again/"&gt;And so it goes, around again&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Charles Miller on Java, pointing out that if you don’t have closures and first-class functions you end up having to add band-aid solutions and special case syntactic sugar. Python’s lack of multi-line lambdas leads to a similar (though less pronounced) effect.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/closures"&gt;closures&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/java"&gt;java&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming-languages"&gt;programming-languages&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;



</summary><category term="charles-miller"/><category term="closures"/><category term="java"/><category term="programming-languages"/><category term="python"/></entry><entry><title>Cluetrainwreck</title><link href="https://simonwillison.net/2008/Apr/19/fishbowl/#atom-tag" rel="alternate"/><published>2008-04-19T08:00:16+00:00</published><updated>2008-04-19T08:00:16+00:00</updated><id>https://simonwillison.net/2008/Apr/19/fishbowl/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://fishbowl.pastiche.org/2008/04/19/cluetrainwreck"&gt;Cluetrainwreck&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Comcast’s official Twitter account is pretty creepy... “I hope we can change your perception of Comcast!”.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cluetrain"&gt;cluetrain&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/comcast"&gt;comcast&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pr"&gt;pr&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;&lt;/p&gt;



</summary><category term="charles-miller"/><category term="cluetrain"/><category term="comcast"/><category term="pr"/><category term="twitter"/></entry><entry><title>Heavier than Air</title><link href="https://simonwillison.net/2008/Jan/22/fishbowl/#atom-tag" rel="alternate"/><published>2008-01-22T01:32:59+00:00</published><updated>2008-01-22T01:32:59+00:00</updated><id>https://simonwillison.net/2008/Jan/22/fishbowl/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://fishbowl.pastiche.org/2008/01/22/heavier_than_air"&gt;Heavier than Air&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Charles Miller points out that every time Apple breaks the mold with a new product (the iPod, the iPod Mini, the iMac and now the MacBook Air) they lose in feature matrix comparisons but win in the marketplace.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apple"&gt;apple&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/imac"&gt;imac&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ipod"&gt;ipod&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ipodmini"&gt;ipodmini&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/macbookair"&gt;macbookair&lt;/a&gt;&lt;/p&gt;



</summary><category term="apple"/><category term="charles-miller"/><category term="imac"/><category term="ipod"/><category term="ipodmini"/><category term="macbookair"/></entry><entry><title>Maven: Broken By Design</title><link href="https://simonwillison.net/2007/Dec/20/maven/#atom-tag" rel="alternate"/><published>2007-12-20T20:24:25+00:00</published><updated>2007-12-20T20:24:25+00:00</updated><id>https://simonwillison.net/2007/Dec/20/maven/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://fishbowl.pastiche.org/2007/12/20/maven_broken_by_design"&gt;Maven: Broken By Design&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Charles Miller: “If you check out a particular version of your code and build it with particular versions of your tools, you should get a product that is binary-identical each time.”


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/buildtools"&gt;buildtools&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/java"&gt;java&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/maven"&gt;maven&lt;/a&gt;&lt;/p&gt;



</summary><category term="buildtools"/><category term="charles-miller"/><category term="java"/><category term="maven"/></entry><entry><title>Understanding Engineers: Feasibility</title><link href="https://simonwillison.net/2007/Jul/17/fishbowl/#atom-tag" rel="alternate"/><published>2007-07-17T10:24:09+00:00</published><updated>2007-07-17T10:24:09+00:00</updated><id>https://simonwillison.net/2007/Jul/17/fishbowl/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://fishbowl.pastiche.org/2007/07/17/understanding_engineers_feasibility"&gt;Understanding Engineers: Feasibility&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Charles Miller provides smart definitions of what programmers mean when they say “impossible”, “trivial”, “unfeasible”, “non-trivial”, “hard” and “very hard”.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hard"&gt;hard&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/language"&gt;language&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nontrivial"&gt;nontrivial&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programmers"&gt;programmers&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming"&gt;programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/trivial"&gt;trivial&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/unfeasible"&gt;unfeasible&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/veryhard"&gt;veryhard&lt;/a&gt;&lt;/p&gt;



</summary><category term="charles-miller"/><category term="hard"/><category term="language"/><category term="nontrivial"/><category term="programmers"/><category term="programming"/><category term="trivial"/><category term="unfeasible"/><category term="veryhard"/></entry><entry><title>Quoting Charles Miller</title><link href="https://simonwillison.net/2007/Jul/12/fishbowl/#atom-tag" rel="alternate"/><published>2007-07-12T17:18:42+00:00</published><updated>2007-07-12T17:18:42+00:00</updated><id>https://simonwillison.net/2007/Jul/12/fishbowl/#atom-tag</id><summary type="html">
    &lt;blockquote cite="http://fishbowl.pastiche.org/2007/07/12/posting_top_like_dont_still_i"&gt;&lt;p&gt;... if you're in an email conversation with one other person and you're both using Gmail, don't bother quoting at all.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="http://fishbowl.pastiche.org/2007/07/12/posting_top_like_dont_still_i"&gt;Charles Miller&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/email"&gt;email&lt;/a&gt;&lt;/p&gt;



</summary><category term="charles-miller"/><category term="email"/></entry><entry><title>Avoiding protracted debates</title><link href="https://simonwillison.net/2004/Mar/21/avoiding/#atom-tag" rel="alternate"/><published>2004-03-21T04:48:25+00:00</published><updated>2004-03-21T04:48:25+00:00</updated><id>https://simonwillison.net/2004/Mar/21/avoiding/#atom-tag</id><summary type="html">
    &lt;p&gt;I love &lt;a href="http://fishbowl.pastiche.org/"&gt;Charles Miller's Fishbowl&lt;/a&gt;. His latest entry introduces his &lt;a href="http://fishbowl.pastiche.org/2004/03/21/charles_rules_of_argument"&gt;rules for argument&lt;/a&gt;. Read them, follow them and save a truck-load of time avoiding protracted debates in the future. Heck, if everyone stuck to them the overall productivity of the internet would probably increase by a factor of ten.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="charles-miller"/></entry><entry><title>Un-happened</title><link href="https://simonwillison.net/2003/Nov/27/unhappened/#atom-tag" rel="alternate"/><published>2003-11-27T16:21:12+00:00</published><updated>2003-11-27T16:21:12+00:00</updated><id>https://simonwillison.net/2003/Nov/27/unhappened/#atom-tag</id><summary type="html">
    &lt;p&gt;Charles Miller, in &lt;a href="http://fishbowl.pastiche.org/2003/11/25/google_microsoft_and_tall_poppies"&gt;Google, Microsoft and Tall Poppies.&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote cite="http://fishbowl.pastiche.org/2003/11/25/google_microsoft_and_tall_poppies"&gt;
&lt;p&gt;Bill Gates' original goal in forming Microsoft was famously to
have (emphasis mine) "A computer on every desk and in every home, &lt;em&gt;running Microsoft software&lt;/em&gt;".
You'll not find the last three words of that sentence in any official
Microsoft history (or at least I couldn't, and I searched hard).
They've been carefully un-happened: the dream of a nascent monopolist
truncated into a facade of altruism.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Google:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;a href="http://www.google.com/search?q=%22desk+and+in+every+home%22+site%3Amicrosoft.com+-%22every+home+running%22"&gt;"desk and in every home" site:microsoft.com -"every home running"&lt;/a&gt; - 167 results&lt;/li&gt;
 &lt;li&gt;&lt;a href="http://www.google.com/search?q=%22desk+and+in+every+home+running%22+site%3Amicrosoft.com"&gt;"desk and in every home running" site:microsoft.com&lt;/a&gt; - 3 results, all from a &lt;a href="http://www.microsoft.com/billgates/speeches/2002/04-25stanford.asp"&gt;Bill Gates speech&lt;/a&gt; at Stanford in 2002.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fascinating.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/computer-history"&gt;computer-history&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/microsoft"&gt;microsoft&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="charles-miller"/><category term="computer-history"/><category term="microsoft"/></entry><entry><title>Supporting Conditional GET in PHP</title><link href="https://simonwillison.net/2003/Apr/23/conditionalGet/#atom-tag" rel="alternate"/><published>2003-04-23T17:22:50+00:00</published><updated>2003-04-23T17:22:50+00:00</updated><id>https://simonwillison.net/2003/Apr/23/conditionalGet/#atom-tag</id><summary type="html">
    &lt;p&gt;This site's &lt;acronym title="Really Simple Syndication"&gt;RSS&lt;/acronym&gt; feeds now support &lt;a href="https://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers" title="HTTP Conditional Get for RSS Hackers"&gt;Conditional GET&lt;/a&gt;. Since the feeds are dynamically generated on every request, adding support took a bit of hacking around with &lt;acronym title="PHP: Hypertext Preprocessor"&gt;PHP&lt;/acronym&gt;. Here's the function I came up with (based on the excellent description provided by Charles Miller in the article linked above):&lt;/p&gt;

&lt;div class="highlight highlight-text-html-php"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;doConditionalGet&lt;/span&gt;(&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;timestamp&lt;/span&gt;) {
    &lt;span class="pl-c"&gt;// A PHP implementation of conditional get, see &lt;/span&gt;
    &lt;span class="pl-c"&gt;//   https://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers&lt;/span&gt;
    &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;last_modified&lt;/span&gt; = substr(date(&lt;span class="pl-s"&gt;'r'&lt;/span&gt;, &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;timestamp&lt;/span&gt;), &lt;span class="pl-c1"&gt;0&lt;/span&gt;, -&lt;span class="pl-c1"&gt;5&lt;/span&gt;).&lt;span class="pl-s"&gt;'GMT'&lt;/span&gt;;
    &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;etag&lt;/span&gt; = &lt;span class="pl-s"&gt;'"'&lt;/span&gt;.md5(&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;last_modified&lt;/span&gt;).&lt;span class="pl-s"&gt;'"'&lt;/span&gt;;
    &lt;span class="pl-c"&gt;// Send the headers&lt;/span&gt;
    header("&lt;span class="pl-s"&gt;Last-Modified: &lt;/span&gt;&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;last_modified&lt;/span&gt;");
    header("&lt;span class="pl-s"&gt;ETag: &lt;/span&gt;&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;etag&lt;/span&gt;");
    &lt;span class="pl-c"&gt;// See if the client has provided the required headers&lt;/span&gt;
    &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;if_modified_since&lt;/span&gt; = isset(&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;&lt;span class="pl-c1"&gt;_SERVER&lt;/span&gt;&lt;/span&gt;[&lt;span class="pl-s"&gt;'HTTP_IF_MODIFIED_SINCE'&lt;/span&gt;]) ?
        stripslashes(&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;&lt;span class="pl-c1"&gt;_SERVER&lt;/span&gt;&lt;/span&gt;[&lt;span class="pl-s"&gt;'HTTP_IF_MODIFIED_SINCE'&lt;/span&gt;]) :
        &lt;span class="pl-c1"&gt;false&lt;/span&gt;;
    &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;if_none_match&lt;/span&gt; = isset(&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;&lt;span class="pl-c1"&gt;_SERVER&lt;/span&gt;&lt;/span&gt;[&lt;span class="pl-s"&gt;'HTTP_IF_NONE_MATCH'&lt;/span&gt;]) ?
        stripslashes(&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;&lt;span class="pl-c1"&gt;_SERVER&lt;/span&gt;&lt;/span&gt;[&lt;span class="pl-s"&gt;'HTTP_IF_NONE_MATCH'&lt;/span&gt;]) : 
        &lt;span class="pl-c1"&gt;false&lt;/span&gt;;
    &lt;span class="pl-k"&gt;if&lt;/span&gt; (!&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;if_modified_since&lt;/span&gt; &amp;amp;&amp;amp; !&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;if_none_match&lt;/span&gt;) {
        &lt;span class="pl-k"&gt;return&lt;/span&gt;;
    }
    &lt;span class="pl-c"&gt;// At least one of the headers is there - check them&lt;/span&gt;
    &lt;span class="pl-k"&gt;if&lt;/span&gt; (&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;if_none_match&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;if_none_match&lt;/span&gt; != &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;etag&lt;/span&gt;) {
        &lt;span class="pl-k"&gt;return&lt;/span&gt;; &lt;span class="pl-c"&gt;// etag is there but doesn't match&lt;/span&gt;
    }
    &lt;span class="pl-k"&gt;if&lt;/span&gt; (&lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;if_modified_since&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;if_modified_since&lt;/span&gt; != &lt;span class="pl-s1"&gt;&lt;span class="pl-c1"&gt;$&lt;/span&gt;last_modified&lt;/span&gt;) {
        &lt;span class="pl-k"&gt;return&lt;/span&gt;; &lt;span class="pl-c"&gt;// if-modified-since is there but doesn't match&lt;/span&gt;
    }
    &lt;span class="pl-c"&gt;// Nothing has changed since their last request - serve a 304 and exit&lt;/span&gt;
    header(&lt;span class="pl-s"&gt;'HTTP/1.0 304 Not Modified'&lt;/span&gt;);
    exit;
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Usage is simple: Work out the timestamp that the page content was last modified and call &lt;code&gt;doConditionalGet($timestamp);&lt;/code&gt;. It will send the 304 header for you and exit if the client claims to have seen the content already - otherwise control will return to your main script and you can serve content as normal. Slightly inelegant, but it does the job.&lt;/p&gt;

&lt;p&gt;Unfortunately I don't have a Conditional-GET supporting &lt;acronym title="Really Simple Syndication"&gt;RSS&lt;/acronym&gt; aggregator to hand so I have no idea if it works or not (so far I've only tested it by watching the headers sent with &lt;a href="http://livehttpheaders.mozdev.org/"&gt;LiveHTTPHeaders&lt;/a&gt;). I'd be grateful if someone could confirm that this has had the desired effect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I've changed the above code sample (and my implementation) to send the ETag header as &lt;code&gt;ETag&lt;/code&gt; rather than &lt;code&gt;etag&lt;/code&gt;.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/charles-miller"&gt;charles-miller&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/etags"&gt;etags&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/php"&gt;php&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rss"&gt;rss&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="charles-miller"/><category term="etags"/><category term="php"/><category term="rss"/></entry></feed>