<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'><id>tag:blogger.com,1999:blog-19303585</id><updated>2008-05-15T15:10:08.963Z</updated><title type='text'>John Graham-Cumming</title><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default?start-index=26&amp;max-results=25'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>167</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-19303585.post-3367906084123517094</id><published>2008-05-15T04:46:00.003Z</published><updated>2008-05-15T07:35:34.846Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>Which countries have the most beautiful women?  (My deeply flawed analysis)</title><content type='html'>So, I happened upon the Wikipedia page about the &lt;a href="http://en.wikipedia.org/wiki/Miss_World"&gt;Miss World&lt;/a&gt; pageant and noticed that it had a list of winners by country.   For example, India has won Miss World 5 times.  But, of course, India has a very large population so you'd expect it to be able to churn out a few beauties.  So, to get a better idea here is a population adjusted list of countries that have won Miss World:&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Country&lt;/th&gt;&lt;th&gt;Wins&lt;/th&gt;&lt;th&gt;Pop.&lt;/th&gt;&lt;th&gt;Wins/Pop.&lt;/th&gt;&lt;th&gt;Normalized&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Bermuda&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;66163&lt;/td&gt;&lt;td&gt;0.0000151141876879827&lt;/td&gt;&lt;td&gt;100.00%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Iceland&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;316252&lt;/td&gt;&lt;td&gt;0.00000948610601672084&lt;/td&gt;&lt;td&gt;62.76%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Grenada&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;110000&lt;/td&gt;&lt;td&gt;0.00000909090909090909&lt;/td&gt;&lt;td&gt;60.15%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Guam&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;173456&lt;/td&gt;&lt;td&gt;0.00000576515081634536&lt;/td&gt;&lt;td&gt;38.14%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Jamaica&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;2651000&lt;/td&gt;&lt;td&gt;0.000001131648434553&lt;/td&gt;&lt;td&gt;7.49%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Trinidad and Tobago&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1305000&lt;/td&gt;&lt;td&gt;0.000000766283524904215&lt;/td&gt;&lt;td&gt;5.07%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Sweden&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;9182927&lt;/td&gt;&lt;td&gt;0.000000326693221017656&lt;/td&gt;&lt;td&gt;2.16%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Puerto Rico&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;3994259&lt;/td&gt;&lt;td&gt;0.000000250359328225836&lt;/td&gt;&lt;td&gt;1.66%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Austria&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;8316487&lt;/td&gt;&lt;td&gt;0.000000240486157195941&lt;/td&gt;&lt;td&gt;1.59%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Ireland&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;4339000&lt;/td&gt;&lt;td&gt;0.000000230467849734962&lt;/td&gt;&lt;td&gt;1.52%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Finland&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;5308208&lt;/td&gt;&lt;td&gt;0.000000188387493481793&lt;/td&gt;&lt;td&gt;1.25%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Venezuela&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;28199822&lt;/td&gt;&lt;td&gt;0.000000177306083705067&lt;/td&gt;&lt;td&gt;1.17%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Israel&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;7282000&lt;/td&gt;&lt;td&gt;0.000000137324910738808&lt;/td&gt;&lt;td&gt;0.91%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Netherlands&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;16408557&lt;/td&gt;&lt;td&gt;0.000000121887622415548&lt;/td&gt;&lt;td&gt;0.81%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Dominican Republic&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;9760000&lt;/td&gt;&lt;td&gt;0.000000102459016393443&lt;/td&gt;&lt;td&gt;0.68%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Czech Republic&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;10381130&lt;/td&gt;&lt;td&gt;0.0000000963286270377117&lt;/td&gt;&lt;td&gt;0.64%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Australia&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;21290000&lt;/td&gt;&lt;td&gt;0.0000000939408172851104&lt;/td&gt;&lt;td&gt;0.62%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Greece&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;11216708&lt;/td&gt;&lt;td&gt;0.0000000891527175353054&lt;/td&gt;&lt;td&gt;0.59%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Peru&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;28674757&lt;/td&gt;&lt;td&gt;0.0000000697477575834383&lt;/td&gt;&lt;td&gt;0.46%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;UK&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;60487300&lt;/td&gt;&lt;td&gt;0.0000000661295842267716&lt;/td&gt;&lt;td&gt;0.44%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Argentina&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;40301927&lt;/td&gt;&lt;td&gt;0.0000000496254186555397&lt;/td&gt;&lt;td&gt;0.33%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;South Africa&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;43700000&lt;/td&gt;&lt;td&gt;0.000000045766590389016&lt;/td&gt;&lt;td&gt;0.30%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Poland&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;38518241&lt;/td&gt;&lt;td&gt;0.0000000259617255107781&lt;/td&gt;&lt;td&gt;0.17%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;France&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;64473140&lt;/td&gt;&lt;td&gt;0.0000000155103350015216&lt;/td&gt;&lt;td&gt;0.10%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Turkey&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;70586256&lt;/td&gt;&lt;td&gt;0.0000000141670639111387&lt;/td&gt;&lt;td&gt;0.09%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Egypt&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;80335036&lt;/td&gt;&lt;td&gt;0.0000000124478689472424&lt;/td&gt;&lt;td&gt;0.08%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Germany&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;82210000&lt;/td&gt;&lt;td&gt;0.0000000121639703199124&lt;/td&gt;&lt;td&gt;0.08%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Russia&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;142008838&lt;/td&gt;&lt;td&gt;0.00000000704181524251329&lt;/td&gt;&lt;td&gt;0.05%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Nigeria&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;148000000&lt;/td&gt;&lt;td&gt;0.00000000675675675675676&lt;/td&gt;&lt;td&gt;0.04%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;US&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;304072000&lt;/td&gt;&lt;td&gt;0.00000000657738956562919&lt;/td&gt;&lt;td&gt;0.04%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Brazil&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;186757608&lt;/td&gt;&lt;td&gt;0.00000000535453420457174&lt;/td&gt;&lt;td&gt;0.04%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;India&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;1132446000&lt;/td&gt;&lt;td&gt;0.00000000441522156464856&lt;/td&gt;&lt;td&gt;0.03%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;China&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1321851888&lt;/td&gt;&lt;td&gt;0.000000000756514409124179&lt;/td&gt;&lt;td&gt;0.01%&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;So, far and away, the top three are Bermuda, Iceland and Grenada.   Given that Bermuda is the winner, and a tax-haven, and has a sub-tropical climate... Hamilton here I come!</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/05/which-countries-have-most-beautiful.html' title='Which countries have the most beautiful women?  (My deeply flawed analysis)'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=3367906084123517094' title='1 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/3367906084123517094'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/3367906084123517094'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-8241096170420061987</id><published>2008-05-01T16:09:00.002Z</published><updated>2008-05-01T16:12:09.694Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='anti-spam'/><title type='text'>The Spammers' Compendium finds a new home</title><content type='html'>Shortly after I announced that I was &lt;a href="http://www.jgc.org/blog/2008/03/retiring-from-anti-spam.html"&gt;getting out of anti-spam&lt;/a&gt; the folks at &lt;a href="http://www.virusbtn.com/"&gt;Virus Bulletin&lt;/a&gt; contacted me about taking over &lt;a href="http://www.jgc.org/tsc.html"&gt;The Spammers' Compendium&lt;/a&gt;.  I was delighted.&lt;br /&gt;&lt;br /&gt;Today the transfer is complete and the new home is &lt;a href="http://www.virusbtn.com/resources/spammerscompendium/index"&gt;here&lt;/a&gt;.   It will be maintained and updated by Virus Bulletin.   Please send submissions to them.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/05/spammers-compendium-finds-new-home.html' title='The Spammers&apos; Compendium finds a new home'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=8241096170420061987' title='4 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8241096170420061987'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8241096170420061987'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-407376232714261198</id><published>2008-04-22T11:39:00.004Z</published><updated>2008-04-22T11:57:58.854Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='my services'/><title type='text'>Bookmark-based registration</title><content type='html'>Recently, I've been learning &lt;a href="http://www.rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; and I can never learn anything unless I build something with it.   I also recently read &lt;a href=""&gt;Programming Collective Intelligence&lt;/a&gt; and had a desire to use some of those algorithms too. &lt;br /&gt;&lt;br /&gt;I'll post more about the actual web site I created another time; currently it's in alpha form running on &lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt;.   The web site is used for naming babies, the initial alpha-release is the girls' names only site &lt;a href="http://emilyoremma.heroku.com/"&gt;EmilyOrEmma?&lt;/a&gt; which uses "Hot or Not" style voting and manages to incorporate in one page the &lt;a href="http://en.wikipedia.org/wiki/Levenshtein_distance"&gt;Levenshtein distance&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Metaphone"&gt;Metaphone&lt;/a&gt; algorithm and both &lt;a href="http://en.wikipedia.org/wiki/Collaborative_filtering"&gt;item-based&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Collaborative_filtering"&gt;user-based filtering&lt;/a&gt;.&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;a href="http://emilyoremma.heroku.com/"&gt;&lt;img src="http://www.jgc.org/blog/babynames1.png" border="0" width="400px"&gt;&lt;/a&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;But my biggest bug bear with baby naming web sites is the need to create an account.  You can browse baby names all you want, but as soon as you want to do something like add a name to a list of favourites you are forced into registration.  Or you don't have to register but anything you do is ephemeral.&lt;br /&gt;&lt;br /&gt;For my site, I came up with a better solution: bookmark-based registration.   If you visit the site you'll see at the bottom of every page a link to bookmark.  This link is unique to you.  It contains your user id and a hash which I used to prevent forgery.   &lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/babynames2.png"&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;Bookmark this link and you can return to your recommendations, saved names, etc. any time.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/04/bookmark-based-registration.html' title='Bookmark-based registration'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=407376232714261198' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/407376232714261198'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/407376232714261198'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-6061648755117990821</id><published>2008-04-08T08:07:00.002Z</published><updated>2008-04-08T09:15:35.772Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>Interesting real-world Apache Problem</title><content type='html'>I'm working with a large client who has a number of web servers behind a load balancer.  This morning one Apache 1.3 had failed to come up on one of them.  The client sends a &lt;a href="http://httpd.apache.org/docs/1.3/programs/apachectl.html"&gt;SIGUSR1&lt;/a&gt; to each Apache once an hour to force a graceful reload.   This particular machine had operated correctly restarting Apache once per hour for 54 hours (since a recent reboot of the machine) and then died.&lt;br /&gt;&lt;br /&gt;A quick look in the Apache &lt;span style="font-family:courier new;"&gt;error.log&lt;/span&gt; file showed the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;module "mod_jk.c" could not be loaded, because the dynamic module limit was reached. Please increase DYNAMIC_MODULE_LIMIT and recompile. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Naturally I went looking for a problem with &lt;a href="http://tomcat.apache.org/connectors-doc/"&gt;mod_jk&lt;/a&gt; which was the wrong place to look.   Scrolling through the log file I noticed that every time Apache restarted we'd get the error:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Cannot remove module mod_include.c: not found in module list&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This was where the real problem lay.  A quick &lt;span style="font-family: courier new;"&gt;httpd -l&lt;/span&gt; showed that &lt;span style="font-family: courier new;"&gt;mod_include&lt;/span&gt; was compiled into the client's Apache and looking in the &lt;span style="font-family: courier new;"&gt;httpd.conf&lt;/span&gt; revealed that &lt;span style="font-family: courier new;"&gt;mod_include&lt;/span&gt; was also being loaded with &lt;a href="http://httpd.apache.org/docs/1.3/mod/mod_so.html"&gt;&lt;span style="font-family: courier new;"&gt;LoadModule&lt;/span&gt;&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;LoadModule includes_module modules/mod_include.so&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When a module is both statically linked into Apache and dynamically loaded you run into a nasty problem: Apache doesn't complain when you start, but it will fail to unload the double loaded module on exit.   So for every &lt;span style="font-family: courier new;"&gt;SIGUSR1&lt;/span&gt; a single slot of the &lt;span style="font-family: courier new;"&gt;DYNAMIC_MODULE_LIMIT&lt;/span&gt; was used up.   The default &lt;a href="http://httpd.apache.org/dev/apidoc/apidoc_DYNAMIC_MODULE_LIMIT.html"&gt;&lt;span style="font-family: courier new;"&gt;DYNAMIC_MODULE_LIMIT&lt;/span&gt;&lt;/a&gt; is 64 and with 10 real dynamic modules and a boot once per hour it took 54 hours to consume every slot in the module limit.&lt;br /&gt;&lt;br /&gt;Removing the errorneous &lt;span style="font-family: courier new;"&gt;LoadModule&lt;/span&gt; fixed the problem.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/04/interesting-real-world-apache-problem.html' title='Interesting real-world Apache Problem'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=6061648755117990821' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/6061648755117990821'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/6061648755117990821'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-6836492735681711805</id><published>2008-04-04T10:40:00.003Z</published><updated>2008-04-04T10:47:08.392Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>Digg 3 Million</title><content type='html'>A quick update on my &lt;a href="http://www.jgc.org/blog/2008/01/how-many-users-does-digg-have.html"&gt;previous estimate of Digg users&lt;/a&gt; shows that, as predicted, Digg passed the 3 million user mark during March, 2008.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/digg-3m.png"&gt;&lt;br /&gt;&lt;br /&gt;Comparing this estimated data and data from the Digg API shows that around 20% of the 3m accounts are not active.  I speculated before that these accounts had been banned for spamming or other activities (that's around 600,000 bad accounts).&lt;br /&gt;&lt;br /&gt;Growth appears to be the same as before adding around 150,000 accounts per month.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/04/digg-3-million.html' title='Digg 3 Million'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=6836492735681711805' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/6836492735681711805'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/6836492735681711805'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-2906738294628449052</id><published>2008-04-03T17:58:00.002Z</published><updated>2008-04-03T18:03:13.211Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>Juxtaposition</title><content type='html'>&lt;img src="http://www.jgc.org/blog/travel-overland.jpg"&gt;</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/04/juxtaposition.html' title='Juxtaposition'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=2906738294628449052' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/2906738294628449052'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/2906738294628449052'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-1850056289290268407</id><published>2008-04-03T10:00:00.002Z</published><updated>2008-04-03T10:16:26.527Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>It's 3am and there's a crisis somewhere in the world</title><content type='html'>If you follow US politics then you'll know that Hillary Clinton has a couple of ads that start with a 3am phone call to the Whitehouse.  The first ad was intended as a slam against Barack Obama implying that he didn't have the experience to deal with such a crisis.  The second is going up against John McCain claiming he doesn't want to do anything about the housing finance problem in the US.&lt;br /&gt;&lt;br /&gt;You know if it's 3am and there's a crisis in the world there's only one place and only one man to call.&lt;br /&gt;&lt;br /&gt;CTU and Jack Bauer.&lt;br /&gt;&lt;br /&gt;First of all, he's already up.  3am is nothing to Jack.  Hillary and McCain both look like they could use the sleep and Obama looks like he gets his beauty sleep every night.  So, Jack's ready to go before any of them.&lt;br /&gt;&lt;br /&gt;As much as you might think Obama is David Palmer (safe pair of hands), he's more like a Wayne Palmer (a slick little fighter) and you know what that means: gets blown up within five minutes of being president and then pops a brain vein and the evil VP has to take over.  The only good thing to say about Obama is that he would call Jack.&lt;br /&gt;&lt;br /&gt;Now, McCain might look like a Bauer type with his military background and heroic time spent as a PoW.  But here's the difference.  McCain was 5 years as a PoW, no one came to get him out so he can't be that valuable.  Also, if Jack had been held hostage in North Vietnam for 5 years there wouldn't be a North Vietnam now.  Because you can bet the life of the next random CTU cast member the Jack would have (a) escaped and (b) annihilated everyone involved.&lt;br /&gt;&lt;br /&gt;So, that leaves Hillary.  She can't tell sniper fire from a little girl with flowers.  In fact she reminds me more and more of the evil Vice Presidents that pop up in every 24 trying to take power from the real president.  Hell, she's probably even got backing from Phillip Bauer.&lt;br /&gt;&lt;br /&gt;Only one word of warning: make sure it's a man that calls Jack.  If it's a woman he's bound to have been involved with her, she'll turn out to be a double agent or her father will be evil, and Jack'll be distracted.&lt;br /&gt;&lt;br /&gt;If it has to be a woman, make sure it's Chloe.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/04/its-3am-and-theres-crisis-somewhere-in.html' title='It&apos;s 3am and there&apos;s a crisis somewhere in the world'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=1850056289290268407' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/1850056289290268407'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/1850056289290268407'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-4192813437577648898</id><published>2008-03-31T14:34:00.006Z</published><updated>2008-03-31T14:41:35.417Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='anti-spam'/><title type='text'>Multi-route (email and phone) self-aware phishing</title><content type='html'>Today, I received the following email:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;This communication was sent to safeguard your account against any&lt;br /&gt;unauthorized activity.&lt;br /&gt;&lt;br /&gt;Max Federal Credit Union is aware of new phishing e-mails&lt;br /&gt;that are circulating. These e-mails request consumers to click&lt;br /&gt;a link due to a compromise of a credit card account.&lt;br /&gt;&lt;br /&gt;You should not respond to this message.&lt;br /&gt;&lt;br /&gt;For your security we have deactivate your card.&lt;br /&gt;&lt;br /&gt;How to activate your card&lt;br /&gt;&lt;br /&gt;Call +1 (800)-xxx-9629&lt;br /&gt;&lt;br /&gt;Our automated system allows you to quickly activate your card&lt;br /&gt;&lt;br /&gt;Card activation will take approximately one minute to complete.&lt;br /&gt;&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/tt&gt;Of course, I don't have an account with &lt;a href="http://www.mymax.com/"&gt;Max Federal Credit Union&lt;/a&gt; and this is obviously a phish.  Notice that the English is quite right:&lt;br /&gt;&lt;br /&gt;"For your security we have &lt;b&gt;deactivate&lt;/b&gt; your card." and "You should not respond to this message." doesn't make sense in context.&lt;br /&gt;&lt;br /&gt;What's more interesting is that the message itself warns you about phishing emails and asks you to call an 800 number. &lt;br /&gt;&lt;br /&gt;If you call the 800 number an electronic voice reminds you again to never give your PIN, password or SSN in &lt;b&gt;email&lt;/b&gt; and then proceeds to ask you for the card number, PIN, expiry date and CVV2.   The assumption is that you've been warned twice not to do something in email, so it's OK by phone.&lt;br /&gt;&lt;br /&gt;It's painful to see the phisher use the existence of phishing as a way to phish.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/multi-route-email-and-phone-self-aware.html' title='Multi-route (email and phone) self-aware phishing'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=4192813437577648898' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/4192813437577648898'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/4192813437577648898'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-8851891060111111947</id><published>2008-03-31T10:05:00.004Z</published><updated>2008-03-31T15:09:28.972Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>Names: Boys vs. Girls</title><content type='html'>Using &lt;a href="http://www.census.gov/genealogy/names/names_files.html"&gt;data from the 1990 US Census&lt;/a&gt; I was amazed to discover that 90% of the US male population has one of 1,219 first names, but 90% of the female population has one of 4,275.    There are 3.5x as many female first names as male first names.&lt;br /&gt;&lt;br /&gt;The top 10 male first names are: James, John, Robert, Michael, William, David, Richard, Charles, Joseph and Thomas (which account for 23.2% of the male population; 50% of the population have one of only 60 names).&lt;br /&gt;&lt;br /&gt;The top 10 female first names are: Mary, Patricia, Linda, Barbara, Elizabeth, Maria, Susan, Margaret and Dorothy (which account for 10.7% of the female population; 50% of the population have on of 139 names).&lt;br /&gt;&lt;br /&gt;You can also see that all the variety in names happens between the 80% and 90%.  For males 80% of the population is covered by 27% of the names; for females 80% is covered by 19% of the names).  &lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/names.png" /&gt;&lt;br /&gt;&lt;br /&gt;The large numbers of female names appears to be because there are lots of variants of female names compared to male names.  A quick run through calculating the &lt;a href="http://en.wikipedia.org/wiki/Levenshtein_distance"&gt;Levenshtein&lt;/a&gt; distance between names and selecting the 10 closest for each gives an average distance of:&lt;br /&gt;&lt;br /&gt;Male: 2.62&lt;br /&gt;Female: 2.01&lt;br /&gt;&lt;br /&gt;So female names are more 'similar' than male names, hence the variety created by all these variants.&lt;br /&gt;&lt;br /&gt;The other thing we can extract from this data is the prevalence of names beginning with certain letters and weight adjust based on the occurrence of each name.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/male_initial.png"&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/female_initial.png"&gt;&lt;br /&gt;&lt;br /&gt;Things are much more polarized when you look at trailing letters (for example, the trailing letter A is an almost sure sign that it's a woman; the opposite is true of D):&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/male_final.png"&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/female_final.png"&gt;&lt;br /&gt;&lt;br /&gt;So combining the two it's possible to give a 'maleness' score (the blue part) to each final letter:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/maleness.png"&gt;</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/names-boys-vs-girls.html' title='Names: Boys vs. Girls'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=8851891060111111947' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8851891060111111947'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8851891060111111947'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-994704005243012725</id><published>2008-03-31T07:57:00.003Z</published><updated>2008-03-31T08:13:28.499Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='bouts'/><title type='text'>BOUTS: The Complete Song Parodies</title><content type='html'>Back when my site &lt;a href="http://www.usethesource.com/"&gt;UseTheSource&lt;/a&gt; was a "blog" (this was late 90s/early naughties) I wrote a number of song parodies.    Someone emailed me and asked where they were.&lt;br /&gt;&lt;br /&gt;So, here are my complete song parodies from back in 2001:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;March 7, 2001: "Candle in the Wind"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Yahoo! was in trouble with banner ad sales falling, profits disappearing and the then CEO, Tim Koogle, was off to spend more time with his family.&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;Goodbye Tim Koogle&lt;br /&gt;Though I never Yahoo! at all&lt;br /&gt;You had the faith, to sell banners&lt;br /&gt;While those around you failed&lt;br /&gt;They crashed into the deadpool&lt;br /&gt;And they whispered into your brain&lt;br /&gt;You need to begin to charge&lt;br /&gt;For things you give for free&lt;br /&gt;&lt;br /&gt;And it seems to me you lived your life&lt;br /&gt;Like a candle in the wind&lt;br /&gt;Never knowing what to add next&lt;br /&gt;To your list of links&lt;br /&gt;And I would have liked to have told you&lt;br /&gt;But I was just a geek&lt;br /&gt;Your web brand burned out long before&lt;br /&gt;Your stock price ever did&lt;br /&gt;&lt;br /&gt;Jerry Yang was tough&lt;br /&gt;The toughest boss you ever had&lt;br /&gt;Softbank created a superstar&lt;br /&gt;And pain was the price you paid&lt;br /&gt;As the whole web died&lt;br /&gt;Oh CNET still hounded you&lt;br /&gt;All they had to say&lt;br /&gt;Was that Google was the site to use&lt;br /&gt;&lt;br /&gt;[Repeat chorus]&lt;br /&gt;&lt;br /&gt;Goodbye Tim Koogle&lt;br /&gt;From the young man on the DSL link&lt;br /&gt;Who sees you as something more successful&lt;br /&gt;More than just our long lost CEO&lt;br /&gt;&lt;br /&gt;[Repeat chorus]&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;b&gt;March 22, 2001: "Don't Cry for Me Argentina"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Steve Jobs was back at Apple, the blue iMac was out, Microsoft was in big anti-trust trouble and had just invested $100m in Apple, Steve had bought out NeXT.   But the future wasn't yet assured:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;This won't be easy,&lt;br /&gt;you'll think it's strange.&lt;br /&gt;When we try to explain what we need&lt;br /&gt;that we now need your help&lt;br /&gt;after all that we've said.&lt;br /&gt;&lt;br /&gt;You won't believe us.&lt;br /&gt;All you'll see is Apple you once knew,&lt;br /&gt;although we've crashed down in the dumps&lt;br /&gt;begging for Microsoft cash.&lt;br /&gt;&lt;br /&gt;It didn't have to happen.&lt;br /&gt;We should have won&lt;br /&gt;Better software and patents than Bill&lt;br /&gt;Looking down on Windows,&lt;br /&gt;staying far from Sun.&lt;br /&gt;So we chose NeXT.&lt;br /&gt;Running aground, trying computers in blue.&lt;br /&gt;But nothing revived us at all.&lt;br /&gt;You never expected it too.&lt;br /&gt;&lt;br /&gt;Don't cry for us, William H. Gates.&lt;br /&gt;The truth is we're dead without you.&lt;br /&gt;We need your dollars&lt;br /&gt;We need Mac Office&lt;br /&gt;You need a rival, for your survival.&lt;br /&gt;&lt;br /&gt;And as for Fortune,&lt;br /&gt;and as for Time,&lt;br /&gt;We never invited them in&lt;br /&gt;though it appeared, to the world,&lt;br /&gt;they were all Steve desired.&lt;br /&gt;Even Adobe,&lt;br /&gt;they're making solutions for Windows right now&lt;br /&gt;The answer was here all the time.&lt;br /&gt;We need you, and hope you need us.&lt;br /&gt;&lt;br /&gt;[chorus]&lt;br /&gt;&lt;br /&gt;Have we begged too much?&lt;br /&gt;There's nothing more we can think of to say to you.&lt;br /&gt;But all you have to do,&lt;br /&gt;is look at us to know,&lt;br /&gt;we're through without you.&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;b&gt;April 1, 2001: "I Just Called To Say I Love You"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In the midst of the crash, .coms were going out of business like crazy:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;No IPO to celebrate&lt;br /&gt;No friends and family stocks and shares to give away&lt;br /&gt;No big opening&lt;br /&gt;No first day ping&lt;br /&gt;In fact here's just another ordinary day&lt;br /&gt;&lt;br /&gt;No Aeron chair&lt;br /&gt;No onsite chef&lt;br /&gt;No working Saturday until the site is done&lt;br /&gt;But what it is, is something blue&lt;br /&gt;Made up of these few words that I must say to you&lt;br /&gt;&lt;br /&gt;We just failed to get more funding&lt;br /&gt;We just failed to keep our doors open&lt;br /&gt;We just failed to get more funding&lt;br /&gt;And we need it just to avoid bankruptcy&lt;br /&gt;&lt;br /&gt;No free massage&lt;br /&gt;No free soda&lt;br /&gt;No caffeine trip to keep us working every night&lt;br /&gt;No dry cleaning&lt;br /&gt;No stock option&lt;br /&gt;Not even time for us to pack our things and leave&lt;br /&gt;&lt;br /&gt;No beanbag room&lt;br /&gt;No Maui trip&lt;br /&gt;No giving thanks to all that NASDAQ did for us&lt;br /&gt;But what it is, though old so new&lt;br /&gt;Grab what you can before your jobs right here are through&lt;br /&gt;&lt;br /&gt;[chorus]&lt;br /&gt;&lt;br /&gt;[chorus]&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;b&gt;April 6, 2001: "Uptown Girl"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ah, to be in love with a marketing .com girl:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt; .com girl&lt;br /&gt;                              She's been living in her .com world&lt;br /&gt;                              I bet she never had a  software guy&lt;br /&gt;                               I bet her mama never told her why&lt;br /&gt;                                 I'm gonna try for a .com girl&lt;br /&gt;                            She's been living in her wide web world&lt;br /&gt;                              As long as anyone in marketing can&lt;br /&gt;                            And now she's looking for a comp. sci. man&lt;br /&gt;                                     That's what I am&lt;br /&gt;&lt;br /&gt;                                  And when she knows what&lt;br /&gt;                                  She wants from her time&lt;br /&gt;                                  And when she wakes up&lt;br /&gt;                                  And makes up her mind&lt;br /&gt;&lt;br /&gt;                                  She'll see I'm not a nerd&lt;br /&gt;                                      Just because&lt;br /&gt;                                 I'm in love with a .com girl&lt;br /&gt;                            You know I've seen her in her online world&lt;br /&gt;                             She's getting tired of her high tech toys&lt;br /&gt;                            And all her presents from her VC boys&lt;br /&gt;                                    She's got a choice&lt;br /&gt;                                       .com girl&lt;br /&gt;                             You know I can't afford to buy her a Porsche&lt;br /&gt;                           But maybe someday when my stock cashes in&lt;br /&gt;                            She'll understand what kind of guy I've been&lt;br /&gt;                                     And then I'll win&lt;br /&gt;&lt;br /&gt;                                  And when she's walking&lt;br /&gt;                                   She's using her Nokia&lt;br /&gt;                                   And when she's talking&lt;br /&gt;                                  She'll say that she's mine&lt;br /&gt;&lt;br /&gt;                                  She'll say I'm not a nerd&lt;br /&gt;                                      Just because&lt;br /&gt;                                       I'm in love&lt;br /&gt;                                    With a .com girl&lt;br /&gt;                            She's been living in her latte world&lt;br /&gt;                              As long as anyone in marketing can&lt;br /&gt;                            And now she's looking for a comp. sci. man&lt;br /&gt;                                     That's what I am&lt;br /&gt;                                       .com girl&lt;br /&gt;                                   She's my .com girl&lt;br /&gt;                                    You know I'm in love&lt;br /&gt;                                    With a .com girl&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;b&gt;April 13, 2001: "Gangsta's Paradise"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Linus Torvalds was the flavor of the day as one of the thorn's in Microsoft's side:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;    As I drive through the Valley of the Silicon Dream&lt;br /&gt;I take a look at my life and realize there's nothing left&lt;br /&gt;'Cause I've been coding and debuggin' so long&lt;br /&gt;That even my manager thinks that my mind has gone&lt;br /&gt;But I ain't never crossed a man that didn't deserve it&lt;br /&gt;Linus treated like a punk, ya know that's unheard of&lt;br /&gt;Ya better watch how ya postin'&lt;br /&gt;And what ya codin'&lt;br /&gt;Or you Dr Tanenbaum'll be lined in chalk&lt;br /&gt;I really hate Minix and FreeBSD&lt;br /&gt;As they croak, I see myself in the pistol smoke&lt;br /&gt;Fool, I'm the kinda hacker script kiddies wanna be like&lt;br /&gt;On the Net in the night, writin' layers of the core code&lt;br /&gt;&lt;br /&gt;CHORUS:&lt;br /&gt;  Been spending most our lives living in a Windows paradise&lt;br /&gt;  Been spending most our lives living in a Windows paradise&lt;br /&gt;  Keep spending most our lives living in Bill Gates' paradise&lt;br /&gt;  Keep spending most our lives living in Bill Gates' paradise&lt;br /&gt;&lt;br /&gt;Look at the situation they got me facing&lt;br /&gt;I can't live a normal life, I was raised on the PC&lt;br /&gt;So I gotta be down with the kernel team&lt;br /&gt;Too much crazy Usenet posting got me chasing dreams&lt;br /&gt;I'm a educated fool with Posix on my mind&lt;br /&gt;Speak Swedish in my home and English on the phone&lt;br /&gt;I'm a loc'd out hacker, wrote my life story&lt;br /&gt;And my homies is down so don't arouse my anger&lt;br /&gt;Fool, death ain't nothin' but a heart beat away&lt;br /&gt;I'm livin' life, do or die, what can I say?&lt;br /&gt;I'm 28 now, but will I ever see 29?&lt;br /&gt;The way things is going, I don't know&lt;br /&gt;&lt;br /&gt;Tell me why are we so blind to see&lt;br /&gt;That Microsoft's a monopoly&lt;br /&gt;&lt;br /&gt;CHORUS&lt;br /&gt;CHORUS&lt;br /&gt;&lt;br /&gt;Tell me why are we so blind to see&lt;br /&gt;That Microsoft's a monopoly&lt;br /&gt;&lt;br /&gt;Tell me why are we so blind to see&lt;br /&gt;That Microsoft's a monopoly&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;b&gt;April 18, 2001: "Copacabana"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Carly Fiorina was fighting for her life as she tried to merge HP and Compaq with Walter Hewlett attempting a proxy fight to stop her in the name of the family:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;Her name was Carly, she was a VP&lt;br /&gt;With Lucent and AT&amp;amp;T and a degree from MIT&lt;br /&gt;She went to HP and wowed the board room&lt;br /&gt;And while she tried to be a star, sometimes went a bit too far&lt;br /&gt;And then September 4, Compaq became the score&lt;br /&gt;They were failing and needed each other&lt;br /&gt;Leaning drunks galore!&lt;br /&gt;&lt;br /&gt;        At the HP, HP/Com-pa-q&lt;br /&gt;        The merger that upset the family&lt;br /&gt;        At the HP, HP/Com-pa-q&lt;br /&gt;        David and William were always the fashion&lt;br /&gt;        At the HP... they ran the show&lt;br /&gt;&lt;br /&gt;His name was Walter, his dad was famous&lt;br /&gt;He wasn't present for the board, but he wouldn't be ignored&lt;br /&gt;And what she pro-posed, "Dad would've hated"&lt;br /&gt;Then Walter went a bit too far, "Carly: time for au revoir!"&lt;br /&gt;And then the insults flew and careers were smashed in two&lt;br /&gt;There were ads and a lot of bankers, but just who screwed who?&lt;br /&gt;&lt;br /&gt;        At the HP, HP/Com-pa-q&lt;br /&gt;        The merger that upset the family&lt;br /&gt;        At the HP, HP/Com-pa-q&lt;br /&gt;        David and Walter are today the fashion&lt;br /&gt;        At the HP... they run the show&lt;br /&gt;&lt;br /&gt;Her name is Carly, she was CEO&lt;br /&gt;But that was 30 weeks ago, when she used to run show&lt;br /&gt;Now she's a VC, but that's our Carly&lt;br /&gt;Still in the suit she used to wear, new blonde highlights in her hair&lt;br /&gt;She sits there so refined, and drinks to Walter's health&lt;br /&gt;She lost her job and she lost the proxy, now she enjoy's her wealth!&lt;br /&gt;&lt;br /&gt;        At the HP, well just the HP&lt;br /&gt;        The toughest job belongs to Walter&lt;br /&gt;        At the HP, well just the HP&lt;br /&gt;        William and David were always the fashion&lt;br /&gt;        At the HP, don't buy the stock...&lt;/tt&gt;&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;If you find these funny and can sing... feel free to set them to music and give me a laugh.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/bouts-complete-song-parodies.html' title='BOUTS: The Complete Song Parodies'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=994704005243012725' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/994704005243012725'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/994704005243012725'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-8680801818121171981</id><published>2008-03-29T16:34:00.003Z</published><updated>2008-03-29T17:08:28.698Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='rants and raves'/><title type='text'>More 11:11 mystical nuttery</title><content type='html'>Out of the blue I received an email about my post the other day about &lt;a href="http://www.jgc.org/blog/2008/02/any-sufficiently-simple-explanation-is.html"&gt;Benford's Law and 11:11&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;every time i look at the clock the number add up to 11. &lt;br /&gt;how does that get explained&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;OK.  Well, it turns out that that's pretty simple to explain: the sum 11 is the most common sum you'll see on a clock.  The following graph shows the count for each sum of digits.  You'll see that for a 12 hour clock the peak is at 11 and for a 24 hour clock the peak is at 12 with 11 being a close second. &lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/1224clock.png" /&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;For a 12 hour clock the probability that the sum of digits will be 128/1440 (or about 9% of the time).   For a 24 hour clock it's 124/1440 (or about 9% of the time).    So it's unsurprising that 11 comes up a lot here.  &lt;br /&gt;&lt;br /&gt;Another area of 11 craziness is airline seating.  This is probably because people get freaked out by flying and look for patterns.   Suppose you sit in economy on a British Airways long haul flight.  You'll be sitting in a 747, 767 or 777.   You then take your seat number add up the digits and then add the letter on using its place in the alphabet (e.g. sitting in 14F then you have 1 + 4 + 6 = 11).   Using the &lt;a href="http://www.britishairways.com/travel/worldt/public/en_us"&gt;British Airways seat maps&lt;/a&gt; you can compute the value of for each seat in economy:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/11seatmaps.png" /&gt;&lt;br /&gt;&lt;br /&gt;On a 767 11 is the most frequently occurring sum, on a 747 it's 10 (with 11 close behind) and on a 777 11 is just beaten out by 12.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/more-1111-mystical-nuttery.html' title='More 11:11 mystical nuttery'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=8680801818121171981' title='1 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8680801818121171981'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8680801818121171981'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-8773279750355514096</id><published>2008-03-25T17:39:00.003Z</published><updated>2008-03-25T17:46:36.883Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='anti-spam'/><title type='text'>"Retiring" from anti-spam</title><content type='html'>Today, I'm "retiring" from anti-spam work.  Practically, that means the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No more updates to The Spammers' Compendium or Anti-spam Tool League Table pages.  These remain on line, but are not being maintained.&lt;/li&gt;&lt;li&gt;I'm looking for a new leader for the POPFile project.&lt;/li&gt;&lt;li&gt;I'm no longer active on any anti-spam mailing lists.&lt;/li&gt;&lt;li&gt;I am leaving all anti-spam conference committees.&lt;/li&gt;&lt;li&gt;My anti-spam newsletter is no longer being published.&lt;/li&gt;&lt;/ul&gt;I will, however, be continuing with commercial anti-spam work where I have agreements currently in place with customers.  No change to their support, terms or assistance.&lt;br /&gt;&lt;br /&gt;The obvious question is why?  For me, the interest just isn't there.  The battle against spam continues but is now about trench warfare rather than creating new weapons.  We'll continue to see innovation, but for any hacker it's the new, new thing that's important.  For me, spam is yesterday's news.  Watching companies squabble and refuse to cooperate, seeing a decline in quality at anti-spam conferences, and major companies essentially killing their consumer anti-spam means anti-spam just isn't where I want to be.&lt;br /&gt;&lt;br /&gt;Of course, there are many really good people fighting spam out there.   This post isn't meant to demean them.&lt;br /&gt;&lt;br /&gt;Thank you to everyone who has supported what I've done over the last 7 years, and good luck!</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/retiring-from-anti-spam.html' title='&quot;Retiring&quot; from anti-spam'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=8773279750355514096' title='5 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8773279750355514096'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8773279750355514096'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-9087740976661540068</id><published>2008-03-22T12:38:00.004Z</published><updated>2008-03-22T15:47:11.058Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='hardware'/><title type='text'>Building a temperature probe for the OLPC XO-1 laptop</title><content type='html'>I bought an &lt;a href="http://en.wikipedia.org/wiki/OLPC_XO-1"&gt;OLPC XO-1&lt;/a&gt; laptop through the &lt;a href="http://laptopgiving.org/en/index.php"&gt;G1G1 program&lt;/a&gt; and was intrigued to discover the &lt;a href="http://wiki.laptop.org/go/Measure"&gt;Measure&lt;/a&gt; activity.&lt;br /&gt;&lt;br /&gt;The measure activity uses the internal audio system to measure a value input on the microphone socket.  With nothing connected this application reads the value of the internal microphone and displays a waveform.  You can have fun just by whistling, speaking or singing with Measure running.&lt;br /&gt;&lt;br /&gt;But since you can measure a voltage input into the microphone socket, it's possible to build sensors and connect them to th OLPC XO-1.   On the Measure web site they mention building a simple &lt;a href="http://wiki.laptop.org/go/Measure#Let.27s_measure_Temperature.21_.28_Featured_activity_of_the_month_.29"&gt;temperature sensor&lt;/a&gt; using an &lt;a href=""&gt;LM35&lt;/a&gt; temperature sensor that looks like this:&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-1.jpg"&gt;&lt;br /&gt;The LM35 can measure a temperature between 0 and 155 Celsius just by hooking it up to a 5v supply.   It outputs 10mv per degree so a temperature of 20 Celsius corresponds to 0.200v.&lt;br /&gt;&lt;br /&gt;Since the OLPC XO-1 has a USB port it's possible to get 5v from the laptop by hacking a USB connector, and connect 5v to the LM35 and then take the signal coming from the LM35 (the middle pin) and connect it to the microphone socket.&lt;br /&gt;&lt;br /&gt;I did this by building two parts: a generic adapter which gives me 5v and a signal line out of a standard stereo 3.5mm jack:&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-2.jpg"&gt;&lt;br /&gt;The stereo jack is wired up so that the tip is +5v, the base is Gnd and the middle is the signal going to the microphone socket.  The USB plug has only two wires connected (for +5v and Gnd), and the jack going to the microphone socket (which is mono) has the connected to the middle of the stereo jack, and the base is Gnd.   All the grounds are joined together.&lt;br /&gt;&lt;br /&gt;When plugged into the OLPC XO-1 it creates a generic connector for any other projects I might work on:&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-3.jpg"&gt;&lt;br /&gt;For the temperature sensor I simply connected the LM35 to a stereo socket with the correct connections to match up with the stereo jack plug.  Then I created a probe with an old plastic pen and some waterproofing compound (so that I can do things like shove the probe in a cup of coffee without wetting the contacts on the LM35).   Here it is:&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-4.jpg"&gt;&lt;br /&gt;Connect the two together and run the standard Measure activity and you can start to look at the output of the sensor and hence the temperature. &lt;br /&gt;&lt;br /&gt;But there's a problem.  The microphone input can only handle voltages in the range &lt;a ref="http://wiki.laptop.org/go/Measure/Hardware"&gt;0.3v to 1.9v&lt;/a&gt; (and my measurements of my OLPC XO-1 show this range to actually be 0.4v to 1.9v).   So that means as is the probe can be used to measure temperatures in the range 40 Celsius to 155 Celsius.   That low end is a bit high for the sorts of experimentation you can do at home (e.g. measure the temperature in the fridge, or a glass of cold water, or even the temperature inside your mouth).&lt;br /&gt;&lt;br /&gt;So we need to scale the voltages coming from the sensor to fit better into the range that's readable by the laptop.   The standard way to do that is with an &lt;a href="http://en.wikipedia.org/wiki/Operational_amplifier"&gt;operational amplifier&lt;/a&gt; which is used to &lt;a href="http://en.wikipedia.org/wiki/Operational_amplifier_applications#Summing_amplifier"&gt;add&lt;/a&gt; two voltages together: the voltage coming from the sensor and a reference voltage.   Doing this will move the voltage up.&lt;br /&gt;&lt;br /&gt;For that I used the &lt;a href="http://www.digchip.com/datasheets/parts/datasheet/161/LM1458N.php"&gt;LM1458&lt;/a&gt; which in a single 8 pin package contains a pair of operational amplifiers.&lt;br /&gt;&lt;br /&gt;Here's the circuit diagram:&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-5.jpg"&gt;&lt;br /&gt;The circuit has three parts: a voltage divider, a summing amplifier and an inverting amplifier.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Voltage divider&lt;/b&gt;: the reference voltage is created by taking the 5v available from the USB port and passing it through resistors R8 and R9.   The voltage at the middle point of these two resistors is determined by the standard formula for a &lt;a href="http://en.wikipedia.org/wiki/Voltage_divider"&gt;voltage divider&lt;/a&gt; of &lt;tt&gt;5v * R9/(R8 + R9) = 5v * 1 / ( 10 + 1 ) = 0.45v&lt;/tt&gt;.   In my actual circuit with 1% tolerance resistors the measured voltage was 0.41v.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Summing amplifier&lt;/b&gt;: the middle portion of the circuit takes the two inputs and adds them together (and because of the nature of the circuit inverts the summed value).  So its output going into R7 is -ve the sum of the reference voltage and the sensor voltage.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Inverting amplifier&lt;/b&gt;: the final part just inverts the voltage so that the output is +ve and in the range that the OLPC XO-1 can read.&lt;br /&gt;&lt;br /&gt;One complexity is that this circuit requires +9v, Gnd and -9v to operate.  I obtain that with a pair of 9v batteries linked together giving Gnd where the two are connected.   Here's the final circuit with appropriate connectors to hook up to my existing probe and laptop adapter:&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-6.jpg"&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-7.jpg"&gt;&lt;br /&gt;And here's what it looks like when it's all hooked together:&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-8.jpg"&gt;&lt;br /&gt;Now, this wouldn't be any fun without a bit of software and since the Measure activity can only display the voltage being presented (which is now a mixture of the sensor voltage and the reference voltage) what's needed as a new activity.&lt;br /&gt;&lt;br /&gt;I found the &lt;a href="http://wiki.laptop.org/go/Developers"&gt;developer&lt;/a&gt; documentation to be very hard to follow and I ended up hacking the existing Measure activity and renaming it Temperature.   &lt;br /&gt;&lt;br /&gt;The critical code is in the file &lt;tt&gt;drawWaveform.py&lt;/tt&gt; where it reads &lt;tt&gt;self.avg&lt;/tt&gt; (the value coming from the microphone input via the ADC) and scale it for display.   I measured voltages coming from my probe for a couple of known temperatures and worked out a scale factor (The +32768 is because the &lt;tt&gt;self.avg&lt;/tt&gt; ranges from -32768 to 32767):&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;  layout.set_text("Temperature: %.1f C" % (0.00221833*(self.avg+32768)) )&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;Here's a screenshot of Temperature running on the laptop and measuring the ambient temperature in my office:&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/temp-9.jpg"&gt;&lt;br /&gt;You can download my &lt;a href="http://www.jgc.org/blog/Temperature.xo"&gt;Temperature&lt;/a&gt; activity using the browser on your OLPC XO-1 to install it.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/building-temperature-probe-for-olpc-xo.html' title='Building a temperature probe for the OLPC XO-1 laptop'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=9087740976661540068' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/9087740976661540068'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/9087740976661540068'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-4236137133596879233</id><published>2008-03-20T13:55:00.002Z</published><updated>2008-03-20T14:08:27.559Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>Sleeping with the enemy</title><content type='html'>I loaded the dish washer:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/dw-1.jpg"&gt;&lt;br /&gt;&lt;br /&gt;My SO loaded the dish washer:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/dw-2.jpg"&gt;&lt;br /&gt;&lt;br /&gt;Who needs help?</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/sleeping-with-enemy.html' title='Sleeping with the enemy'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=4236137133596879233' title='1 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/4236137133596879233'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/4236137133596879233'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-2796913839307034502</id><published>2008-03-11T19:02:00.004Z</published><updated>2008-03-11T20:05:25.131Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='rants and raves'/><category scheme='http://www.blogger.com/atom/ns#' term='anti-spam'/><title type='text'>First assume all new email is useless</title><content type='html'>When I download email none of it goes in my Inbox.  In fact, I don't have an Inbox.  I work on the assumption that all new email is useless.&lt;br /&gt;&lt;br /&gt;Many reports tell us that between 80% and 90% of all email is spam, so for starters only 10% to 20% is at all likely to be useful.   Then, if you account for being on mailing lists, being CC:ed needlessly and receiving automatic updates such as order confirmations from Amazon.com, you'll see that almost all email is useless.  Only a tiny fraction of the mail you receive is useful.   And by useful I mean &lt;i&gt;requiring action&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;I use Thunderbird and my email folder structure looks like this:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/noinbox.png" /&gt;&lt;br /&gt;&lt;br /&gt;When email arrives it is automatically sorted using &lt;a href="http://getpopfile.org/"&gt;POPFile&lt;/a&gt; into the folders: Family, GNU Make, Misc, polymail, POPFile and Spam.   These six folders are the categories of mail that I receive:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;b&gt;POPFile&lt;/b&gt;: Since I wrote POPFile I get lots of mail about it and I use this is a general box for other open source projects I work on and anything else about anti-spam&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;polymail&lt;/b&gt;: Anything to do with my commercial product &lt;a href="http://www.extravalent.com/"&gt;polymail&lt;/a&gt; and my consulting business&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;GNU Make&lt;/b&gt;: Anything to do with GNU Make or the company, &lt;a href="http://www.electric-cloud.com/"&gt;Electric Cloud&lt;/a&gt;, that I co-founded&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Family&lt;/b&gt;: Anything from my family&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Misc&lt;/b&gt;: Order confirmations, airline tickets, PayPal statements, etc.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Spam&lt;/b&gt;: spam&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;POPFile uses Naive Bayesian text classification to automatically sort my email (with just a point and click interface for training) and then six rules (which never need updating) move the incoming mail based on POPFile's classification to one of those folders.&lt;br /&gt;&lt;br /&gt;Of course, POPFile can be used to sort mail in any way you choose: my categories are unlikely to be yours.   You might use POPFile to sort Work from Home from Spam.  At least one journalist I know uses POPFile to sort Interesting from Boring from Spam so that he only gets to read interesting press releases.&lt;br /&gt;&lt;br /&gt;When I identify mail that does need action taken I move it to the ACTION folder (which is the closest I've got to an Inbox).    Moving mail there is a snap because I use the &lt;a href="https://addons.mozilla.org/en-US/thunderbird/addon/877"&gt;QuickMove&lt;/a&gt; extension for Thunderbird and have ALT-number keys mapped to each folder: one key press and the message is moved into or out of ACTION.&lt;br /&gt;&lt;br /&gt;To keep on top of things I &lt;a href="http://www.jgc.org/blog/2007/06/measuring-my-inbox-depth.html"&gt;publish&lt;/a&gt; the number of items in my ACTION folder on my web site.  Here's a live view over the last 24 hours.   Currently, 9 items need dealing with.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://212.69.38.60/inbox/inbox-daily.png" /&gt;&lt;br /&gt;&lt;br /&gt;My rules for managing email:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Assume that all new email is useless&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Automatically sort email into folders on delivery&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Take control of your Inbox: only you put email in it&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/first-assume-all-new-email-is-useless.html' title='First assume all new email is useless'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=2796913839307034502' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/2796913839307034502'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/2796913839307034502'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-1205876757662065543</id><published>2008-03-10T23:07:00.002Z</published><updated>2008-03-10T23:14:52.500Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='rants and raves'/><title type='text'>Why Rails rules: continuous forward motion</title><content type='html'>Lately I've been playing with &lt;a href="http://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; and I'm impressed.  Not by the documentation (I was pulling my hair out trying to map my copy of the Rails book that deals with 1.x to Rails 2.0 installed on my machine).  Not by the screencasts, or by DHH being arrogant.&lt;br /&gt;&lt;br /&gt;I'm impressed by the fact that Rails keeps you (or at least me) in continuous forward motion.&lt;br /&gt;&lt;br /&gt;Yesterday sitting in an airport I decided to learn Rails.  I had the two books (one on Ruby, one on Rails) which I'd read before, but I'd never actually coded anything.  I had an idea for an application that was CRUD worthy.&lt;br /&gt;&lt;br /&gt;Tonight, after a total of 4 hours of programming I have a working application in Rails that allows me to track health care expenses (appointments, bills, insurance reimbursements, payments, ...).   Zero knowledge to working application in four hours isn't meant to illustrate my genius, it illustrates that Rails/Ruby is easy to learn and that the combination of generators and scaffolding keep you moving.&lt;br /&gt;&lt;br /&gt;I've noticed in the past when working on apps that I'll come up against a difficult bit and go work on something easier ("Oh, I don't want to come up with foo-bar algorithm right now, I'll go design the buttons").  And the easier things are lower value.&lt;br /&gt;&lt;br /&gt;Rails keeps me going after the functionality because it puts in place most of the functionality and then lets me evolve it.   My application looks horrible (I've wasted no time on the CSS or HTML), but the functionality is there.  &lt;br /&gt;&lt;br /&gt;Some sleep and a little design work and it'll look like something.&lt;br /&gt;&lt;br /&gt;Anyone else like access to a free application for health care expense management?</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/why-rails-rules-continuous-forward.html' title='Why Rails rules: continuous forward motion'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=1205876757662065543' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/1205876757662065543'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/1205876757662065543'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-362335354728559958</id><published>2008-03-03T09:31:00.003Z</published><updated>2008-03-03T09:38:22.210Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='anti-spam'/><title type='text'>To the idiotic spammer posting comment spam on this site</title><content type='html'>Since your name is &lt;a href="http://www.blogger.com/profile/15469803290087254615/"&gt;two Chinese characters&lt;/a&gt; I'm going to address you as "Dude".&lt;br /&gt;&lt;br /&gt;Dude,&lt;br /&gt;&lt;br /&gt;Lately you've been posting comment spam on my blog for your World of Warcraft Gold.  This is a little silly:&lt;br /&gt;&lt;br /&gt;1. I'm fairly well known in anti-spam circles, did you really think I was going to let comment spam through on this site?&lt;br /&gt;&lt;br /&gt;2. Comment moderation is turned &lt;b&gt;on&lt;/b&gt; on this site.  So your comment spam goes nowhere when I click the Discard button.&lt;br /&gt;&lt;br /&gt;3. There has been a little some collateral damage from your World of Warcraft spamming.  I accidentally killed two comments by &lt;a href="http://www.blogger.com/profile/03234197014388443076/"&gt;Hypermechanic&lt;/a&gt; and I can't retrieve them.  He/she wanted to say something useful about &lt;a href="http://www.jgc.org/blog/2008/02/tonight-im-going-to-write-myself-aston.html"&gt;an old post&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;You could do that like cameroid.com .&lt;br /&gt;I guess in JAVA or .NET.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Cool I will hunt for it… This is a very sweet look app you have here. Even though you down play your role this is still brilliant.&lt;br /&gt;&lt;br /&gt;Thank you for something new and useful.&lt;br /&gt;&lt;/blockquote&gt;</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/03/to-idiotic-spammer-posting-comment-spam.html' title='To the idiotic spammer posting comment spam on this site'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=362335354728559958' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/362335354728559958'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/362335354728559958'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-1988290144855941889</id><published>2008-02-28T13:44:00.004Z</published><updated>2008-02-28T14:22:59.165Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>Any sufficiently simple explanation is indistinguishable from magic</title><content type='html'>Well, that's true if you are a fool.&lt;br /&gt;&lt;br /&gt;Take for example the mystical belief that the number 11 or 11:11 is somehow significant.   Uri Geller goes on about this on &lt;a href="http://www.uri-geller.com/articles/11.htm"&gt;his web site&lt;/a&gt;.  To quote from Geller's web site (and you'll find other similar thinking on many 11:11 web sites):&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;String theory is said to be the theory of everything. It is a way of describing every force and matter regardless of how large or small or weak or strong it is. There are a few eleven's that have been found in string theory.&lt;br /&gt;&lt;br /&gt;I find this to be interesting since this theory is supposed to explain the universe! The first eleven that was noticed is that string theory has to have 11 parallel universes (discussed in the beginning of the "11.11" article) and without including these universes, the theory does not work.&lt;br /&gt;&lt;br /&gt;The second is that Brian Greene has 11 letters in his name. For those of you who do not know, he is a physicist as well as the author of The Elegant Universe, which is a book explaining string theory. (His book was later made into a mini series that he hosted.) Another interesting find is that Isaac Newton (who's ideas kicked off string theory many years later) has 11 letters in his name as well as John Schwarz. Schwarz was one of the two men who worked out the anomalies in the theory. Plus, 1 person + 1 person = 2 people = equality.&lt;br /&gt;&lt;br /&gt;Also, the two one's next to each other is 11. The two men had to find the same number (496) on both sides of the equation in order for the anomalies to be worked out, so the &lt;b&gt;equation had to have equality! There were two matching sides to the equation as well&lt;/b&gt; because they ultimately got 496 on both sides. So, the 1 + 1 = 2 = equality applies for the equation as well.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;I added a little bold type there because it amused me; pity that Mr Geller didn't look up the definition of equation before writing that line.&lt;br /&gt;&lt;br /&gt;But key to this whole belief is that the number 11 keeps turning up at random.  When I first read about this I looked up at the clock and it was 11:43.  Whoa!  Spooky!&lt;br /&gt;&lt;br /&gt;But then I remembered &lt;a href="http://en.wikipedia.org/wiki/Benford%27s_law"&gt;Benford's Law&lt;/a&gt;.   Benford's Law is essentially that in lots of real-life data the leading digit is 1 with a probability of about 30% (instead of the 10% you'd expect if the first digit was random from 0 through 9) and hence numbers beginning with 1 occur more often than numbers starting with any other digit.&lt;br /&gt;&lt;br /&gt;A simple illustration is my clock experience.  What's the probability that if you look at a clock at random that the first digit is a 1?   Well it's more likely than any other number.&lt;br /&gt;&lt;br /&gt;For a clock showing 12 hour time it cycles through: 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11.  A simple count will show you that the number 1 is the first digit for 8 out of the 24 hours and that all the other digits occur 2 times in 24 hours.   So what's the probability that if I glance at a clock at random I'll see a 1 at the beginning? 8/24 or 1/3 of the time... which is Benford's Law.&lt;br /&gt;&lt;br /&gt;Now, Benford's Law isn't restricted to time.  It occurs all over the place (Wikipedia lists: electricity bills, street addresses, stock prices, population numbers, death rates, lengths of rivers, physical and mathematical constants) and so if you walk through life looking at random numbers you'll see numbers starting with a 1 more often than any other number.   In 1988 a mathematician named &lt;a href="http://www.math.gatech.edu/%7Ehill/Academics.html"&gt;Ted Hill&lt;/a&gt; showed why this is the case for many real-world systems.&lt;br /&gt;&lt;br /&gt;But, what about 11? I hear you ask.  Well if the first digit is more likely to be 1 than any other than it's clear that you are more likely to see numbers in the range 10 through 19 more than other two digit numbers, but a more interesting offshoot of Benford's Law is explained &lt;a href="http://www.mathpages.com/home/kmath302/kmath302.htm"&gt;here&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Essentially as you walk through the digits of a number you are more likely to see a 1 than another digit, but that effect diminishes the longer the number gets.  The probability that the the second digit is a 1 is about 11% (instead of the expected 10%) and given that the probability that the first digit is a 1 is 30% you are bound to come across 11 more frequently than you'd expect (if numbers were random).&lt;br /&gt;&lt;br /&gt;So, it's no surprise that we see lots of 11s, and hence there's a simple explanation for all those 11s.   Either that or I've been missing the call of the &lt;a href="http://1111spiritguardians.com/"&gt;11:11 Spirit Guardians&lt;/a&gt; all these years:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;These 11:11 Wake-Up Calls on your digital clocks, mobile phones, VCR’s and microwaves are the "trademark" prompts of a group of just 1,111 fun-loving Spirit Guardians, or Angels. Once they have your attention, they will use other digits, like 12:34, or 2:22 to remind you of their presence. Invisible to our eyes, they are very real.&lt;br /&gt;&lt;/blockquote&gt;</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/02/any-sufficiently-simple-explanation-is.html' title='Any sufficiently simple explanation is indistinguishable from magic'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=1988290144855941889' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/1988290144855941889'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/1988290144855941889'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-4499447323550414053</id><published>2008-02-27T06:48:00.005Z</published><updated>2008-03-03T09:28:16.607Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>Would they hide me?</title><content type='html'>This is pretty much exclusively a technical blog, but I was very struck by something legendary investor &lt;a href="http://en.wikipedia.org/wiki/Warren_Buffett"&gt;Warren Buffett&lt;/a&gt; said when &lt;a href="http://undergroundvalue.blogspot.com/2008/02/notes-from-buffett-meeting-2152008_23.html"&gt;answering the question&lt;/a&gt; "How do you define happiness and what about your life makes you most happy?":&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;I know a woman in her 80’s, a Polish Jew woman forced into a concentration camp with her family but not all of them came out. She says, “I am slow to make friends because when I look at people, I have one question in mind; would they hide me?” If you get to be my age, or younger for that matter, and have a lot of people that would hide you, then you can feel pretty good about how you’ve lived your life. &lt;br /&gt;&lt;br /&gt;I know people on the Forbes 400 list whose children would not hide them. “He’s in the attic, he’s in the attic.” Some of them keep compensating by joining board seats or getting honorary degrees, but it doesn’t change the fact that no one will give a damn when they are gone. The most powerful force in the world is unconditional love. To hoard it is a terrible mistake in life. The more you try to give it away, the more you get it back.&lt;br /&gt;&lt;/blockquote&gt;</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/02/would-they-hide-me.html' title='Would they hide me?'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=4499447323550414053' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/4499447323550414053'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/4499447323550414053'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-4085169993649827849</id><published>2008-02-14T08:35:00.003Z</published><updated>2008-02-14T09:04:51.923Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>The sum of the first n odd numbers is always a square</title><content type='html'>I was staring at the checked pattern on the back of an airline seat the other day when I suddenly saw that the sum of the first &lt;tt&gt;n&lt;/tt&gt; odd numbers is always a square.  For example,&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1&lt;br /&gt;1 + 3 = 4&lt;br /&gt;1 + 3 + 5 = 9&lt;br /&gt;1 + 3 + 5 + 7 = 16&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And, of course, it occurred to me that it would be nice to be able to prove it.  There are lots of ways to do that.  Firstly, this is just the sum of an &lt;a href="http://en.wikipedia.org/wiki/Arithmetic_progression"&gt;arithmetic progression&lt;/a&gt; starting at &lt;tt&gt;a = 1&lt;/tt&gt; with a difference of &lt;tt&gt;d = 2&lt;/tt&gt;.  So the standard formula gives us:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sum_odd(n) = n(2a + (n-1)d)/2&lt;br /&gt;           = n(2 + (n-1)2)/2&lt;br /&gt;           = n(1 + n - 1)&lt;br /&gt;           = n^2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So, the sum of the first &lt;tt&gt;n&lt;/tt&gt; odd numbers is &lt;tt&gt;n^2&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;But using standard formulae is annoying, so how about trying a little induction.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sum_odd(1) = 1&lt;br /&gt;&lt;br /&gt;sum_odd(n+1) = sum_odd(n) + (2n + 1)&lt;br /&gt;             = n^2 + 2n + 1&lt;br /&gt;             = (n+1)^2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But back to the airline seat.  Here's what I saw (I added the numbering, Lufthansa isn't kind enough to do that for you :-):&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/oddsquare-1.png"&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;The other thing I noticed was this:&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/oddsquare-2.png"&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;You can view the square as the sum of two simpler progressions (the sum of the first &lt;tt&gt;n&lt;/tt&gt; numbers and the sum of the first &lt;tt&gt;n-1&lt;/tt&gt; numbers):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1 + 3 + 5 + 7 =&lt;br /&gt;1 + 2 + 3 + 4 +&lt;br /&gt;    1 + 2 + 3&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And given that we know from Gauss the sum of the first &lt;tt&gt;n&lt;/tt&gt; numbers if &lt;tt&gt;n(n+1)/2&lt;/tt&gt; we can easily calculate:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sum_odd(n) = sum(n) + sum(n-1)&lt;br /&gt;           = n(n+1)/2 + (n-1)n/2&lt;br /&gt;           = (n^2 + n + n^2 - n)/2&lt;br /&gt;           = n^2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What do you do on long flights?</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/02/sum-of-first-n-odd-numbers-is-always.html' title='The sum of the first n odd numbers is always a square'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=4085169993649827849' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/4085169993649827849'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/4085169993649827849'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-6351920688180203252</id><published>2008-02-13T09:15:00.004Z</published><updated>2008-02-13T12:37:36.758Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><title type='text'>Tonight, I'm going to write myself an Aston Martin</title><content type='html'>This is the story of my attempt to 'cheat' in an on-line &lt;a href="http://en.wikipedia.org/wiki/Spot_the_ball_competition"&gt;spot-the-ball&lt;/a&gt; competition to win an &lt;a href="http://www.astonmartin.com/"&gt;Aston Martin&lt;/a&gt;.  It's also the story of my failure, but you get free source code that implements automatic detection of image alteration using copy/paste or tools like the &lt;a href="http://en.wikipedia.org/wiki/Clone_tool"&gt;Clone Tool&lt;/a&gt; in Photoshop.&lt;br /&gt;&lt;br /&gt;First, take a look at this photo:&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/copymove-1.png"&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;Notice anything strange?  In fact this image has been tampered with to cover up a truck.  The truck is completely hidden by foliage.  Here's the original:&lt;br /&gt;&lt;center&gt; &lt;br /&gt;&lt;img src="http://www.jgc.org/blog/copymove-2.png"&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;Wouldn't it be nice to be able to detect that automatically?  It is possible.  Here's an image automatically generated by my code showing what was moved.  All of the red was moved to the blue (or the other way around).&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/copymove-3.png"&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;I was motivated to work on this program by greed (or at least my never-ending love of having a little flutter on things).  &lt;a href="http://www.bestofthebest.co.uk/"&gt;Best of the Best&lt;/a&gt; runs spot-the-ball competitions in airports to win very expensive cars.  But they also run the same competition online.   That meant I could get my hands on the actual image used... could I process it to discover where the ball had been removed?  (In reality, this isn't the right way to win because the actual ball position is not governed by where it actually was, but where a judge thinks it was).&lt;br /&gt;&lt;br /&gt;Would it be cheating if I could?  Apparently not, the competition rules say I should use my skill and judgment in determining the ball position.  Surely, skill covers my programming ability.&lt;br /&gt;&lt;br /&gt;So, I went looking for tampering algorithms and eventually came across &lt;a href="http://www.ws.binghamton.edu/fridrich/Research/copymove.pdf"&gt;Detection of Copy-Move Forgery in Digital Images&lt;/a&gt; written by &lt;a href="http://www.ws.binghamton.edu/fridrich/"&gt;Jessica Fridrich&lt;/a&gt; at SUNY Binghamton.  The paper describes an algorithm for detecting just the sort of changes I thought I was looking for.&lt;br /&gt;&lt;br /&gt;Unfortunately, I know nothing about image processing.  Fortunately, the paper is written in a very clear style and a bit of Internet research enabled me to track down the knowledge I didn't have.  (Also, thanks to Jessica for sending me the original images she used to test my implementation).&lt;br /&gt;&lt;br /&gt;In brief the algorithm does the following:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Slide a 16x16 block across the entire image from left hand corner to bottom right hand corner.  For each 16x16 block perform a &lt;a href="http://en.wikipedia.org/wiki/Discrete_cosine_transform"&gt;discrete cosine transform&lt;/a&gt; (DCT) on it and then &lt;a href="http://en.wikipedia.org/wiki/Quantization_%28image_processing%29"&gt;quantize&lt;/a&gt; the 16x16 block using an expanded version of the standard JPEG quantization matrix.&lt;br /&gt;&lt;br /&gt;&lt;li&gt; Each quantized DCT transformed block is stored in a matrix with one row per (x,y) position in the original image (the (x,y) being the upper left hand corner of the 16x16 block being examined).&lt;br /&gt;&lt;br /&gt;&lt;li&gt; The resulting matrix is lexicographically sorted and then rows that match in the matrix are identified.  For each pair of matching rows (x1,y1) and (x2,y2) the shift vector (x1-x2,y1-y2) (normalized by swapping if necessary so that the first value is +ve) is computed and for each shift vector a count is kept of the number of times it is seen.&lt;br /&gt;&lt;br /&gt;&lt;li&gt; Finally the shift vectors with a count &amp;gt; some threshold are examined, the corresponding pair of positions in the image are found and the 16x16 blocks they represent are highlighted.&lt;/ol&gt;&lt;br /&gt;Here's another picture showing a golfing image that's been touched up to remove something from the grass:&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;img src="http://www.jgc.org/blog/copymove-4.png"&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;img src="http://www.jgc.org/blog/copymove-5.png"&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;To get access to image data I used the &lt;a href="http://freeimage.sourceforge.net/"&gt;FreeImage&lt;/a&gt; library and wrote a small C program that implements Jessica's algorithm.  You can download the source &lt;a href="http://www.jgc.org/blog/copymove.c"&gt;here&lt;/a&gt;; it's released to you under the GNU GPL.&lt;br /&gt;&lt;br /&gt;The program has two key parameters that affect how the image is processed: the &lt;b&gt;quality factor&lt;/b&gt; and the &lt;b&gt;threshold&lt;/b&gt;.   &lt;br /&gt;&lt;br /&gt;The &lt;b&gt;quality factor&lt;/b&gt; is a number used to 'blur' the image (actually it changes the quantization): the higher the factor the more blurring and hence more 16x16 blocks are likely to seem the same to the algorithm.  Increasing the &lt;b&gt;quality factor&lt;/b&gt; will tend to increase the false matches.&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;threshold&lt;/b&gt; is simply the number of blocks that have to appear to have been copied together.  This prevents us from seeing a single 16x16 block as evidence of copying.  Increasing the &lt;b&gt;threshold&lt;/b&gt; means ever larger groups of blocks have to be identified together before they are identified as copying.&lt;br /&gt;&lt;br /&gt;Back at &lt;i&gt;Best of the Best&lt;/i&gt; I grabbed the image for &lt;a href="http://www.bestofthebest.co.uk/botb2/site/public/previousGame.acds?instanceid=4098263"&gt;Supercar Competition (SC-272)&lt;/a&gt;, cut out a section that I thought the ball had to be in (just to speed up processing) and ran the algorithm.  After some parameter tweaking the algorithm came up only with what look like false matches to me (along the bar where it's all one color):&lt;br /&gt;&lt;center&gt;&lt;br /&gt;&lt;img src="http://www.jgc.org/blog/copymove-6.png"&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;And, of course, that's not where the judge thought the ball was.  So, I guess I won't be driving home in the &lt;a href="http://www.astonmartin.com/thecars/v8vantage"&gt;V8 Vantage&lt;/a&gt;, but what geek needs that when they've got a cool piece of software that detects copy/move forgery in images?&lt;br /&gt;&lt;br /&gt;Which leaves me with one question: how are spot-the-ball images generated?  Is this an algorithm problem, a problem because they use JPG (which is already transformed) for their images, or are these images generated in some other way?</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/02/tonight-im-going-to-write-myself-aston.html' title='Tonight, I&apos;m going to write myself an Aston Martin'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=6351920688180203252' title='18 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/6351920688180203252'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/6351920688180203252'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-3559916719159368819</id><published>2008-02-12T21:28:00.000Z</published><updated>2008-02-12T21:57:57.213Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><category scheme='http://www.blogger.com/atom/ns#' term='arc'/><title type='text'>Interface to SQLite database in 23 lines of Arc</title><content type='html'>One thing that the first release of &lt;a href="http://arclanguage.org/"&gt;Arc&lt;/a&gt; was missing was access to any sort of database, but that's easily remedied.  Here are 23 lines of Arc code that provide access to a &lt;a href="http://www.sqlite.org/"&gt;SQLite&lt;/a&gt; database:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(= db! 'nil)&lt;br /&gt;&lt;br /&gt;(def db+ (name (o host "localhost") (o port 49153))&lt;br /&gt; (let (i o) (connect-socket host port)&lt;br /&gt;   (db&amp;gt; o name)&lt;br /&gt;   (if (db&amp;lt; i) (list i o))))&lt;br /&gt;&lt;br /&gt;(def sql ((i o) q)&lt;br /&gt; (db&amp;gt; o q)&lt;br /&gt; (if (db&amp;lt; i) (readall i 200)))&lt;br /&gt;&lt;br /&gt;(def db- (db)&lt;br /&gt; (map close db))&lt;br /&gt;&lt;br /&gt;(def db&amp;gt; (o s)&lt;br /&gt; (write s o)&lt;br /&gt; (writec #\return o)&lt;br /&gt; (writec #\newline o)&lt;br /&gt; (flush-socket o))&lt;br /&gt;&lt;br /&gt;(def db&amp;lt; (i)&lt;br /&gt; (= db! (read i))&lt;br /&gt; (iso db! 200))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The three functions you need to care about are &lt;tt&gt;db+&lt;/tt&gt; (get a connection to a named SQLite database), &lt;tt&gt;db-&lt;/tt&gt; (close a connection to a database) and &lt;tt&gt;sql&lt;/tt&gt; (execute a SQL query and return a list (or lists) of rows.   There's also &lt;tt&gt;db!&lt;/tt&gt; which contains the status of the last command (200 for OK, or 500 followed by a string explaining the error).&lt;br /&gt;&lt;br /&gt;Here's a little Arc session creating a database, putting some data in it and then querying it.  The database called &lt;tt&gt;test&lt;/tt&gt; didn't exist at the start of this session:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;arc&amp;gt; (= db (db+ "test"))&lt;br /&gt;(#&amp;lt;input-port&amp;gt; #&amp;lt;output-port&amp;gt;)&lt;br /&gt;arc&amp;gt; (sql db "create table foo (id integer primary key, text varchar(255))")&lt;br /&gt;nil&lt;br /&gt;arc&amp;gt; (sql db "select * from foo")&lt;br /&gt;nil&lt;br /&gt;arc&amp;gt; (sql db "insert into foo (text) values ('first');")&lt;br /&gt;nil&lt;br /&gt;arc&amp;gt; (sql db "select * from foo")&lt;br /&gt;(("1" "first"))&lt;br /&gt;arc&amp;gt; (sql db "insert into foo (text) values ('something else')")       &lt;br /&gt;nil&lt;br /&gt;arc&amp;gt; (sql db "select * from foo")&lt;br /&gt;(("1" "first") ("2" "something else"))&lt;br /&gt;arc&amp;gt; (db- db)&lt;br /&gt;nil&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To make this work I had to write a TCP server that wraps SQLite (it's just a small C program that you can get &lt;a href="http://www.jgc.org/blog/sqarc.zip"&gt;here&lt;/a&gt;).  The C program listens on a port for connections from your Arc program and handles queries.&lt;br /&gt;&lt;br /&gt;I did have to make a small patch to Arc itself (since arc0 doesn't contain any outgoing socket code).  My patch adds the ability to make a TCP connection to a remote machine and to flush an output port (add this to your &lt;tt&gt;ac.scm&lt;/tt&gt;):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(xdef 'connect-socket (lambda (host port)&lt;br /&gt;       (let-values ([(in out) (tcp-connect host port)]) (list in out))))&lt;br /&gt;(xdef 'flush-socket (lambda (s) (flush-output s)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(Apologies if I have abused Scheme there, I'm a Scheme n00b)&lt;br /&gt;&lt;br /&gt;All this code is released under the same license as Arc itself.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/02/interface-to-sqlite-database-in-23.html' title='Interface to SQLite database in 23 lines of Arc'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=3559916719159368819' title='3 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/3559916719159368819'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/3559916719159368819'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-7710787106114725094</id><published>2008-02-12T08:59:00.000Z</published><updated>2008-02-12T09:53:17.841Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>The leakiness of web mail</title><content type='html'>Many people seem to use web mail systems like &lt;a href="http://hotmail.com/"&gt;Hotmail&lt;/a&gt; or &lt;a href="http://mail.yahoo.com/"&gt;Yahoo! Mail&lt;/a&gt; as a way of providing anonymity.   This is a mistake because all these systems leak the IP address of the machine the user is typing on!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Hotmail&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Here are part of the headers of a message that a family member sent me from their Hotmail account:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC;&lt;br /&gt;Received: from 134.151.225.153 by lw14fd.law14.hotmail.msn.com with HTTP;&lt;br /&gt;X-Originating-IP: [134.151.225.153]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This leaks that original IP address (134.151.225.153) twice: once in an &lt;tt&gt;X-Originating-IP&lt;/tt&gt; header and once in the first &lt;tt&gt;Received&lt;/tt&gt; header which indicates that it was received from the same IP address using HTTP (i.e. using the web).   A quick lookup shows that that IP address is in &lt;a href="http://www.geoiptool.com/en/?IP=134.151.225.153"&gt;Birmingham, UK&lt;/a&gt; (which I happen to know is correct).  So, if they were trying to keep their location secret, they've failed.  &lt;br /&gt;&lt;br /&gt;A &lt;a href="http://en.wikipedia.org/wiki/WHOIS"&gt;whois&lt;/a&gt; lookup on that IP address tells me even more information, including that fact that is belongs to an &lt;a href="http://www.aston.ac.uk/"&gt;Aston University&lt;/a&gt;.  So, it's easy to conclude that this family member was student or staff at that university.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Yahoo! Mail&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Yahoo! Mail leaks in a similar way.  Here are part of the headers of a message I received from someone with what looks like a random email address and no name:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Received: from [193.95.59.139] by web25709.mail.ukl.yahoo.com via HTTP;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Geo locating that IP address shows me that the writer is in &lt;a href="http://www.geoiptool.com/en/?IP=193.95.59.139"&gt;Tunisia&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Another Yahoo! Mail leak from an old colleague in California let's me track down their &lt;a href="http://www.geoiptool.com/en/?IP=67.102.112.112"&gt;home city&lt;/a&gt; from their DSL line.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Received: from [67.102.112.112] by web14204.mail.yahoo.com via HTTP;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;AOL Mail&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Here are some headers from a message sent from an AOL web mail account that reveal that the sender is in &lt;a href="http://www.geoiptool.com/en/?IP=62.128.31.9"&gt;Germany&lt;/a&gt; and looks like it gives away the name of the company that they are working for in the DNS name of the machine:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;X-MB-Message-Source: WebUI&lt;br /&gt;X-AOL-IP: 62.128.31.9&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;tt&gt;X-AOL-IP&lt;/tt&gt; gives the IP address of the machine that generated the message (i.e. where the web browser is running) and the helpful &lt;tt&gt;X-MB-Message_Source&lt;/tt&gt; tells us they are using the web interface.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Earthlink&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Here's an email I received from the editor of Wired who was using Earthlink:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Nice one! When I get off dialup from the French countryside, I'll blog&lt;br /&gt;that...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Was he really in France?&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;X-Originating-IP: 213.11.198.147&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.geoiptool.com/en/?IP=213.11.198.147"&gt;Yes&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Others&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;A search of my own email showed me that &lt;tt&gt;X-Originating-IP&lt;/tt&gt; is a popular leak point (used by Inbox.com, kth.se, Network Solutions, MSN.com and others).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Google Mail and Hushmail&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Neither &lt;a href="http://mail.google.com/"&gt;Google Mail&lt;/a&gt; nor &lt;a href="http://hushmail.com/"&gt;Hushmail&lt;/a&gt; appear to leak the IP address.  They may include the IP address (for example, in the &lt;tt&gt;Message-ID&lt;/tt&gt;) but it does not appear to be readily discoverable.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/02/leakiness-of-web-mail.html' title='The leakiness of web mail'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=7710787106114725094' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/7710787106114725094'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/7710787106114725094'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-8382631845787448471</id><published>2008-02-11T18:00:00.000Z</published><updated>2008-02-12T22:00:06.027Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='pseudo-randomness'/><category scheme='http://www.blogger.com/atom/ns#' term='arc'/><title type='text'>My first Arc project: a simple Wiki</title><content type='html'>The only way to learn a programming language is to write something in it.  So, I decided it was time to dig into &lt;a href="http://arclanguage.org/"&gt;Arc&lt;/a&gt; and my first project is a very simple Wiki.&lt;br /&gt;&lt;br /&gt;Here's the source (&lt;tt&gt;wiki.arc&lt;/tt&gt;):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;; A wiki written in Arc (arc0)&lt;br /&gt;;&lt;br /&gt;; Copyright (c) 2008 John Graham-Cumming&lt;br /&gt;;&lt;br /&gt;; (load "wiki.arc")&lt;br /&gt;; (wsv)&lt;br /&gt;;&lt;br /&gt;; Then go to http://localhost:8080/show&lt;br /&gt;&lt;br /&gt;(load "web.arc")&lt;br /&gt;(load "util.arc")&lt;br /&gt;&lt;br /&gt;(= pagedir* "wiki/")&lt;br /&gt;&lt;br /&gt;(def histfiles (page)&lt;br /&gt;  (sort &gt; (map [coerce _ 'int] (rem [is "current" _] (dir (pagepath page))))))&lt;br /&gt;&lt;br /&gt;(def nexthist (page)&lt;br /&gt;  (let h (histfiles page)&lt;br /&gt;    (if h (++ (car h)) 0)))&lt;br /&gt;&lt;br /&gt;(def pagepath (page)&lt;br /&gt;  (string pagedir* (page 0) "/" (page 0) (page 1) "/" page ))&lt;br /&gt;&lt;br /&gt;(def pagefile (page (o file))&lt;br /&gt;  (string (pagepath page) "/" (or file "current")))&lt;br /&gt;&lt;br /&gt;(def slurp (page (o file))&lt;br /&gt;  (if &lt;br /&gt;  (let p (pagefile page file)&lt;br /&gt;    (if (file-exists p) (readfile p)))))&lt;br /&gt;&lt;br /&gt;(def upperlen (word)&lt;br /&gt;  (len (keep upper word)))&lt;br /&gt;&lt;br /&gt;(def is-wikilink (word)&lt;br /&gt;  (if (alphas word)&lt;br /&gt;    (if (~is (word 0) (downcase (word 0)))&lt;br /&gt;      (&gt;= (upperlen word) 2))))&lt;br /&gt;&lt;br /&gt;(mac url-show (page)&lt;br /&gt;  `(string "show?p=" ,page))&lt;br /&gt;&lt;br /&gt;(mac url-edit (page)&lt;br /&gt;  `(string "edit?p=" ,page))&lt;br /&gt;&lt;br /&gt;(mac link-show (page text)&lt;br /&gt;  `(link ,text (url-show ,page)))&lt;br /&gt;&lt;br /&gt;(mac link-edit (page text)&lt;br /&gt;  `(link ,text (url-edit ,page)))&lt;br /&gt;&lt;br /&gt;(def wikify (word)&lt;br /&gt;  (if (is-wikilink word)&lt;br /&gt;    (if (file-exists (pagefile word))&lt;br /&gt;      (link-show word word)&lt;br /&gt;      (pr word)(link-edit word "?"))&lt;br /&gt;    (pr word))&lt;br /&gt;  (ws))&lt;br /&gt;&lt;br /&gt;(mac spew-raw (page)&lt;br /&gt;  `(spew ,page [pr _ " "]))&lt;br /&gt;&lt;br /&gt;(mac spew-wiki (page (o file))&lt;br /&gt;  `(spew ,page [wikify (string _)] ,file))&lt;br /&gt;&lt;br /&gt;(def spew (page f (o file))&lt;br /&gt;  (let p (pagepath page)&lt;br /&gt;  (if (dir-exists p) &lt;br /&gt;    (map f (flat (map tokens (slurp page file))))&lt;br /&gt;    (pr "This page does not yet exist."))))&lt;br /&gt;&lt;br /&gt;(def squash (file body)&lt;br /&gt;  (writefile1 body file))&lt;br /&gt;&lt;br /&gt;(def save-page (req)&lt;br /&gt;  (w/$ p&lt;br /&gt;    (w/$ t&lt;br /&gt;      (squash (pagefile p) t)&lt;br /&gt;      (squash (string (pagepath p) "/" (nexthist p)) t))&lt;br /&gt;    (url-show p)))&lt;br /&gt;&lt;br /&gt;(mac mtime (f)&lt;br /&gt;  `(datetime (file-mtime ,f)))&lt;br /&gt;&lt;br /&gt;(def last-modified (page)&lt;br /&gt;  (let f (pagefile page)&lt;br /&gt;    (if (file-exists f) &lt;br /&gt;      (pr "Last modified: " (mtime f)))))&lt;br /&gt;&lt;br /&gt;(mac show-page (page)&lt;br /&gt;  `(whitepage&lt;br /&gt;    (tag h1 (link-show ,page ,page))&lt;br /&gt;    (spew-wiki ,page)&lt;br /&gt;    (br 2)&lt;br /&gt;    (hr)&lt;br /&gt;    (last-modified ,page)&lt;br /&gt;    (br)&lt;br /&gt;    (link-edit ,page "[edit]")&lt;br /&gt;    (ws)&lt;br /&gt;    (link "[history]" (string "history?p=" ,page))))&lt;br /&gt;&lt;br /&gt;(mac edit-page (page)&lt;br /&gt;  `(whitepage&lt;br /&gt;   (tag h1 (pr (string "Editing " ,page)))&lt;br /&gt;   (arform save-page &lt;br /&gt;     (textarea "t" 25 80 (spew-raw ,page))&lt;br /&gt;     (hidden "p" ,page)&lt;br /&gt;     (br)&lt;br /&gt;     (submit "Save"))&lt;br /&gt;     (link-show ,page "[cancel]")&lt;br /&gt;   (br 2)))&lt;br /&gt;&lt;br /&gt;(def revision (page rev)&lt;br /&gt;  (tag li&lt;br /&gt;    (pr "Revision: " )&lt;br /&gt;    (link rev (string "revision?p=" page "&amp;r=" rev))&lt;br /&gt;    (pr " modified " (mtime (string (pagepath page) "/" rev)))))&lt;br /&gt;&lt;br /&gt;(mac history-page (page)&lt;br /&gt;  `(whitepage&lt;br /&gt;   (tag h1 (pr (string "History of " ,page)))&lt;br /&gt;   (tag ul (map [revision ,page _] (histfiles ,page)))&lt;br /&gt;   (hr)&lt;br /&gt;   (link-show ,page (string "Back to " ,page))))&lt;br /&gt;&lt;br /&gt;(mac revision-page (page rev)&lt;br /&gt;  `(whitepage&lt;br /&gt;    (tag h1 (pr "Showing revision " ,rev " of " ,page))&lt;br /&gt;    (spew-wiki ,page ,rev)&lt;br /&gt;    (br 2)&lt;br /&gt;    (hr)&lt;br /&gt;    (last-modified ,page)&lt;br /&gt;    (br)&lt;br /&gt;    (link-show ,page (string "Back to " ,page))))&lt;br /&gt;&lt;br /&gt;(defop show req&lt;br /&gt;  (w/$ p&lt;br /&gt;    (if p&lt;br /&gt;      (show-page ($ "p"))&lt;br /&gt;      (show-page "HomePage"))))&lt;br /&gt;&lt;br /&gt;(defop edit req&lt;br /&gt;  (w/$ p&lt;br /&gt;    (ensure-dir (pagepath p))&lt;br /&gt;    (edit-page p)))&lt;br /&gt;&lt;br /&gt;(defop history req&lt;br /&gt;  (history-page ($ "p")))&lt;br /&gt;&lt;br /&gt;(defop revision req&lt;br /&gt;  (revision-page ($ "p") ($ "r")))&lt;br /&gt;&lt;br /&gt;(def wsv ()&lt;br /&gt;  (ensure-dir pagedir*)&lt;br /&gt;  (asv))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It loads two helpers.  The first contains common utilities that aren't really Wiki-related (&lt;tt&gt;util.arc&lt;/tt&gt;):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(def alpha (c)&lt;br /&gt;  (or (&lt;= #\a c #\z) (&lt;= #\A c #\Z)))&lt;br /&gt;&lt;br /&gt;(def alphas (str)&lt;br /&gt;  (is (keep alpha str) str))&lt;br /&gt;&lt;br /&gt;(def upper (c)&lt;br /&gt;  (is (upcase c) c))&lt;br /&gt;&lt;br /&gt;(def datetime ((o time (seconds)))&lt;br /&gt;  (let val (tostring&lt;br /&gt;    (system (string "date -u -r " time " \"+%Y-%m-%d %H:%M\"")))&lt;br /&gt;      (subseq val 0 (- (len val) 1))))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And the second contains enhancement to Arc's web/HTML handling (&lt;tt&gt;web.arc&lt;/tt&gt;):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(mac hidden (name val)&lt;br /&gt;  `(gentag input type 'hidden name ,name value ,val))&lt;br /&gt;&lt;br /&gt;(mac hr ()&lt;br /&gt;  `(gentag hr))&lt;br /&gt;&lt;br /&gt;(mac ws ()&lt;br /&gt;  `(pr " "))&lt;br /&gt;&lt;br /&gt;(mac $ (r)&lt;br /&gt;  `(arg req ,r))&lt;br /&gt;&lt;br /&gt;(mac w/$ (r . body)&lt;br /&gt;  `(with (,r ($ (string ',r))) ,@body))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In &lt;tt&gt;web.arc&lt;/tt&gt; there are a couple of bits of syntax to make accessing form/URL arguments easier: &lt;tt&gt;($ "p")&lt;/tt&gt; (which gets the value of the argument &lt;tt&gt;p&lt;/tt&gt;) and &lt;tt&gt;(w/$ p ...)&lt;/tt&gt; which sets a variable called &lt;tt&gt;p&lt;/tt&gt; to the value of the argument &lt;tt&gt;p&lt;/tt&gt; and then evaluates the rest of the expression.&lt;br /&gt;&lt;br /&gt;All this is released under the same license as Arc.  (Since I have never programmed in Arc before, and it's been almost 20 years since I stopped coding in LISP or ML, I'd appreciate constructive comments).</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/02/my-first-arc-project-simple-wiki.html' title='My first Arc project: a simple Wiki'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=8382631845787448471' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8382631845787448471'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8382631845787448471'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-19303585.post-8586427042213806730</id><published>2008-02-11T08:38:00.000Z</published><updated>2008-02-11T17:59:22.741Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>PPP3 (final version) in Java and C</title><content type='html'>&lt;a href="http://www.grc.com/"&gt;Steve Gibson&lt;/a&gt; has released the final version of his PPP system: &lt;a href="http://www.grc.com/ppp.htm"&gt;PPPv3&lt;/a&gt; and so I've updated my &lt;a href="http://www.jgc.org/blog/2007/11/steve-gibsons-ppp-new-version-3-in-java.html"&gt;code&lt;/a&gt; to be compatible.&lt;br /&gt;&lt;br /&gt;Two versions of PPPv3 are available:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The &lt;a href="http://www.jgc.org/blog/pppv3-c.zip"&gt;C version&lt;/a&gt;&lt;br /&gt;&lt;li&gt;The &lt;a href="http://www.jgc.org/blog/pppv3-java.zip"&gt;Java version&lt;/a&gt;&lt;br /&gt;&lt;li&gt;The &lt;a href="http://www.jgc.org/blog/pppv3.jar"&gt;Compiled Java&lt;/a&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Both are released, as before, under the BSD license.</content><link rel='alternate' type='text/html' href='http://www.jgc.org/blog/2008/02/ppp3-in-java-and-c.html' title='PPP3 (final version) in Java and C'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19303585&amp;postID=8586427042213806730' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.jgc.org/blog/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8586427042213806730'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19303585/posts/default/8586427042213806730'/><author><name>John Graham-Cumming</name><email>noreply@blogger.com</email></author></entry></feed>