<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4259015877647291249</id><updated>2012-02-16T15:02:38.668-07:00</updated><category term='ruby'/><category term='firefox'/><category term='lisp'/><category term='emacs'/><category term='javascript'/><category term='mercurial'/><category term='general'/><category term='python'/><category term='notes'/><title type='text'>defcraft</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://defcraft.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>48</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-2821665239937188305</id><published>2010-12-05T11:23:00.004-07:00</published><updated>2010-12-05T11:39:44.599-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Two useful scripts</title><content type='html'>&lt;p&gt;Here are two Ruby scripts that I find useful. Both of them have been tested under Ruby 1.9.2p0. The first is &lt;b&gt;mv_ldown&lt;/b&gt;: it moves the most recently downloaded file (from ~/Downloads) into the current directory.
&lt;/p&gt;
&lt;pre class="codebox"&gt;
#! /usr/bin/env ruby
src = Dir[File.expand_path('~/Downloads/*')].
  sort_by { |x| File.mtime(x) }.
  last
abort("nothing in ~/Downloads dir") unless src
dest = File.join(File.absolute_path('.'), File.basename(src))
abort("#{dest} already exists") if File.exists?(dest)
File.rename(src, dest)
puts "#{File.basename src} to ."
&lt;/pre&gt;

&lt;p&gt;
The second is &lt;b&gt;sl&lt;/b&gt;: it just like the command "&lt;b&gt;ln -s SRC DEST&lt;/b&gt;", but you don't have to remember the order of the parameters. The file that exists is the source and the other, the destination.&lt;/p&gt;

&lt;pre class="codebox"&gt;
#! /usr/bin/env ruby
require 'fileutils'
abort("Usage: sl SRC DEST") unless ARGV.length == 2
a, b = ARGV
if File.exists?(a) &amp;amp;&amp;amp; File.exists?(b)
  abort("Both #{a} &amp;amp; #{b} exists")
elsif File.exists?(a)
  src, dest = a, b
elsif File.exists?(b)
  src, dest = b, a
else
  abort("Neither #{a} nor #{b} exists")
end
src = File.absolute_path src
abort("#{src} not a file") unless File.file?(src)
dest = File.absolute_path dest
system("ln -s #{src} #{dest}")

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-2821665239937188305?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2821665239937188305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2821665239937188305'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2010/12/two-useful-scripts.html' title='Two useful scripts'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-6913982777103705738</id><published>2010-03-03T19:51:00.006-07:00</published><updated>2010-03-05T00:06:47.710-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Extracting phone numbers from Outlook Msg Files</title><content type='html'>&lt;p&gt;Recently, I had to extract phone numbers from a bunch of Outlook .MSG files (see &lt;a href="http://msdn.microsoft.com/en-us/library/cc463912(EXCHG.80).aspx"&gt;here&lt;/a&gt; and &lt;a href="http://www.fileformat.info/format/outlookmsg/"&gt;here&lt;/a&gt;). 
&lt;/p&gt;

&lt;p&gt;
Looking for an open source solution, I came across &lt;a href="http://auxilii.com/msgparser/"&gt;MsgParser&lt;/a&gt;. It almost did what I needed. (I just had to modify a "protected" field and make it "public" -- I needed to access it from a driver program; there might be a easier way to do this -- maybe make the driver program "run" from the same package as MsgParser and it'll have access to the protected field...) But downloading its dependencies was a bit of a pain.
&lt;/p&gt;

&lt;p&gt;So here is a Ruby script that does all that for you. You specify a directory where the Outlook .MSG files are. It'll extract all the phone numbers from them and print it. Tested under OS X Leopard; needs curl &amp;amp; java to be installed. Run: &lt;span style="font-weight:bold;"&gt;ruby msg_extractor.rb MSGS_DIR&lt;/span&gt;.
&lt;/p&gt;

&lt;pre class="codebox"&gt;
# Released under the GNU GPL.
# http://www.gnu.org/copyleft/gpl.html

require 'fileutils'

DOWNLOADS = %w{
  http://auxilii.com/msgparser/download/msgparser-1.6.zip
  http://www.freeutils.net/source/jtnef/jtnef-1_6_0.zip
  http://apache.ziply.com/poi/release/bin/poi-bin-3.6-20091214.tar.gz
  http://www.trieuvan.com/apache/ant/binaries/apache-ant-1.8.0-bin.zip }

JCLASS = 'MyMsgParser'
JAVA_INPUT = 'My.msg'
JAVA = &amp;lt;&amp;lt;END
  import java.util.*;
  import com.auxilii.msgparser.*;
  import com.auxilii.msgparser.attachment.*;
  public class #{JCLASS} {
    public static void main(String[] args) throws Exception{
      MsgParser msgp = new MsgParser();
      Message msg = msgp.parseMsg("#{JAVA_INPUT}");
      // UNUSED
      String fromEmail = msg.getFromEmail();
      String fromName = msg.getFromName();
      String subject = msg.getSubject();
      String body = msg.getBodyText();
      String longString = msg.toLongString();
      // We modify source of msgparser to make
      // properties public
      Iterator it = msg.properties.keySet().iterator();
      while (it.hasNext()) {
       String key = (String) it.next();
       Object val = msg.properties.get(key);
        System.out.println(key + ": " + val);
      }
    }
  }
END

class MsgExtractor
  def initialize(msgs_dir)
    @msgs_dir = msgs_dir
    @cp = '.:msgparser-1.6/dist/msgparser-1.6.jar:' + 
          'poi-3.6/poi-3.6-20091214.jar:lib/tnef.jar'
    download
    javac
  end
  
  def download
    DOWNLOADS.each do |u|
      b = File.basename(u)
      if !File.exists?(b)
        puts "downloading #{u}"
        `curl --silent -O #{u}` unless File.exists?(b)
      end
      next if File.exists?("#{b}.zipped")
      puts "unpacking #{b}"
      case b
      when /zip$/; `unzip -o #{b}`
      when /gz$/;  `gzip -dc #{b} | tar -xpvf -`
      end
      FileUtils.touch("#{b}.zipped")
    end
  end
  
  def javac
    modify_msgparser
    @cp.split(':').each do |f|
      abort("#{f} doesn't exist") unless File.exists?(f) 
    end
    open("#{JCLASS}.java", "w") { |f| f.write(JAVA) }
    `javac -classpath #{@cp} #{JCLASS}.java`
  end
  
  def modify_msgparser
    jp = 'msgparser-1.6/src/main/java/com/auxilii/msgparser/Message.java'
    old1 = 'protected Map&amp;lt;String,Object&amp;gt; properties ' + 
           '= new HashMap&amp;lt;String,Object&amp;gt;();'
    new1 = old1.dup
    new1['protected'] = 'public'
    modified = File.read(jp)
    return if modified[new1]
    modified[old1] = new1
    puts "modifying #{jp}..."
    open(jp, 'w') { |f| f.write(modified) }
    FileUtils.cd('msgparser-1.6') do
      puts "rebuilding msgparser"
      `../apache-ant-1.8.0/bin/ant jar`
      FileUtils.mv 'dist/msgparser.jar', 'dist/msgparser-1.6.jar'
    end
  end
  
  def run(&amp;amp;extract_by)
    result = []
    Dir[File.join(@msgs_dir, '*.msg')].each do |f|
      b = File.basename(f)[0..-5]
      puts "extracting #{b}"
      FileUtils.cp(f, JAVA_INPUT)
      out = `java -classpath #{@cp} #{JCLASS}`
      data = extract_by.call(out)
      next if data.nil?
      break if $INTERRUPTED
      result &amp;lt;&amp;lt; [b, data]
    end
    result.sort
  end
end

$INTERRUPTED = false

def main
  unless ARGV[0]
    abort("Usage: ruby msgs_extractor.rb msgs_dir")
  end
  tmp = ARGV[1] || "msgs_extractor"
  Dir.mkdir tmp rescue nil
  msgs_dir = File.expand_path ARGV[0]
  Dir.chdir tmp
  extractor = MsgExtractor.new(msgs_dir)
  trap("INT") { $INTERRUPTED = true; puts; }
  result = extractor.run { |o| o.scan /\d{7,20}/ } # extract phone numbers
  result.each { |n, ph| puts("%20s: %s" % [n, ph.join(", ")]) }
end

if $0 == __FILE__
  main
end

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-6913982777103705738?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6913982777103705738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6913982777103705738'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2010/03/extracting-phone-numbers-from-outlook.html' title='Extracting phone numbers from Outlook Msg Files'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7368709474603815688</id><published>2009-10-14T21:50:00.005-07:00</published><updated>2009-10-14T22:03:25.679-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Don't Make Me Think</title><content type='html'>I loved &lt;a href="http://www.amazon.com/Dont-Make-Me-Think-Usability/dp/0321344758"&gt;Don't Make Me Think&lt;/a&gt;. It takes you inside the mind of the user (of your website). And it tells you who they are, what they expect and what confuses them. And the golden rule is, of course, don't make them think.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7368709474603815688?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7368709474603815688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7368709474603815688'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/10/dont-make-me-think.html' title='Don&apos;t Make Me Think'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4350077573618675376</id><published>2009-10-11T14:57:00.005-07:00</published><updated>2009-10-11T15:10:26.676-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Some videos</title><content type='html'>&lt;p&gt;Lately, I've been watching some cool videos on software development. Here they are, along with my notes on them:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://37signals.com/svn/posts/1952-i-gave-a-talk-on-ui-fundamentals-for-programmers"&gt;UI Fundamentals for Programmers&lt;/a&gt;, by &lt;a href="http://rjs.tumblr.com/"&gt;Ryan Singer&lt;/a&gt;.
&lt;pre class="codebox"&gt;
Base UI on a Model
Be explicit and use a lot of language.
Break screens out w/ REST
Least Effective Difference
Screen -- design from the inside out
Flows - think about actions. Split
every action into 3:
 1. start: how to i get to it?
 2. middle: post note.
 3. end: where do it go afterwards?
Fonts:
Small sizes, &amp;lt; 10px, Verdana. But not so good for larger sizes.
Lucida Grande lot
&lt;/pre&gt;

&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://blog.businessofsoftware.org/2009/07/seth-godins-talk-from-business-of-software-2008.html"&gt;Why marketing is too important to be left to the marketing department&lt;/a&gt;, by &lt;a href="http://sethgodin.typepad.com/"&gt;Seth Godin&lt;/a&gt;.


&lt;pre class="codebox"&gt;
Ideas that spread, win.
Build marketing into the software.
Make it connect.
TV thinking -- average products for average people.
If you're gonna interrupt everyone, you'll have a product everyone will 
will wanna to buy.
You're solving a problem that most people don't think that they have.
Clutter is not your friend.
You deal with clutter by making more clutter.

Do something totally different.
And people will talk about it.
At the edges, people wait in line.

Don't force new medium, but
build stuff that fits the new medium.

You are in the story telling business.

Hard to make money in the middle.

The new way:
(1) be remarkable -- encourages people to talk about it
(2) tell a story about it
(3) THEY spread the word
(4) and THEY come for another story

Build a tribe: help people connect
with each other.
Build a tribe: stand up for something
remarkable.

&lt;/pre&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4350077573618675376?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4350077573618675376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4350077573618675376'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/10/some-videos.html' title='Some videos'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-2733254173094853839</id><published>2009-09-21T01:18:00.002-07:00</published><updated>2009-09-21T01:29:08.623-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Manuel Blum's Advice to new Grad Students</title><content type='html'>I liked &lt;a href="http://www.cs.cmu.edu/%7Emblum/research/pdf/grad.html"&gt;this collection&lt;/a&gt; of advice to grad students. Some quotes:
&lt;ul style="font-style: italic;"&gt;&lt;li&gt;Books are not scrolls. [...]          Permit yourself to open a book and start reading from anywhere.
     In the case of mathematics or physics or anything especially hard, try          to find something anything that you can understand.&lt;/li&gt;&lt;li&gt;Consider writing what you read as you read it. This is especially true if you're intent on reading something hard.&lt;/li&gt;&lt;li&gt;I once asked Umesh Vazirani how he was able, as an undergraduate at MIT, to take 6 courses each and every semester. He said that he knew he didn't have the time to work out his answers the hard way. He had to find a shortcut. You see, Umesh understood that problems often have short clever solutions.
&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-2733254173094853839?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2733254173094853839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2733254173094853839'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/09/manuel-blums-advice-to-new-grad.html' title='Manuel Blum&apos;s Advice to new Grad Students'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7123103430063895615</id><published>2009-09-08T12:25:00.006-07:00</published><updated>2009-09-08T14:21:38.656-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Hacker News bookmarklet</title><content type='html'>A bookmarklet for &lt;a href="http://news.ycombinator.com"&gt;Hacker News&lt;/a&gt;.&lt;br/&gt;
It helps you read comments. It does 4 things:
&lt;ul&gt;
&lt;li&gt;sort by root comment, newest to oldest (byParent)&lt;/li&gt;
&lt;li&gt;sort by latest reply in comment thread, newest to oldest (byReply)&lt;/li&gt;
&lt;li&gt;shows you how many people have replied to your comment (example "4 replies")&lt;/li&gt;
&lt;li&gt;updates page with new comments and marks them as such (reload)&lt;/li&gt;
&lt;/ul&gt;

Here is the bookmarklet: &lt;a href="javascript:javascript:(function()%20{%20var%20gParent%20=%20null;%20var%20gReplies%20=%200;%20var%20gTree%20=%20null;%20var%20gComments%20=%20null;%20var%20gOldComments%20=%20[];%20var%20COMMENT_RE%20=%20/(\d+)%20points?%20by%20([^\s]+)%20(\d+)%20(\w+)%20ago/;%20function%20Comment()%20{%20this.points%20=%200;%20this.user%20=%20%22%22;%20this.secs%20=%200;%20this.elt%20=%20null;%20this.ancestor%20=%20null;%20/*%20a%20child%20of%20gParent%20*/%20this.children%20=%20[];%20this.level%20=%200;%20this.txt%20=%20%22%22;%20this.deleted%20=%20false;%20this.as_array%20=%20function(a)%20{%20if%20(!a)%20a%20=%20[];%20a.push(this);%20for%20(var%20i=0;%20i&lt;this.children.length;%20i++)%20this.children[i].as_array(a);%20return%20a;%20};%20this.latest%20=%20function()%20{%20var%20min%20=%20this.secs;%20for%20(var%20i=0;%20i&lt;this.children.length;%20i++)%20min%20=%20Math.min(min,%20this.children[i].latest());%20return%20min;%20};%20}%20function%20findParent(all,%20level)%20{%20if%20(level%20&lt;=%200)%20return%20null;%20for%20(var%20i=all.length-1;%20i&gt;=0;%20i--)%20{%20var%20com%20=%20all[i];%20if%20(com.level%20&lt;%20level)%20return%20com;%20}%20return%20null;%20}%20function%20markReply(e)%20{%20e.style.borderTop%20=%20%271px%20solid%20#ff6600%27;%20}%20function%20markNew(e)%20{%20e.style.borderTop%20=%20%271px%20solid%20#0000ee%27;%20}%20function%20unmarkOld(e)%20{%20e.style.borderTop%20=%200;%20}%20function%20gui()%20{%20var%20div%20=%20document.createElement(%22div%22);%20var%20sep%20=%20function()%20{%20div.appendChild(document.createTextNode(%22\u00A0\u00A0%22));%20};%20div.style.position%20=%20%22fixed%22;%20div.style.bottom%20=%200;%20div.style.right%20=%200;%20div.style.padding%20=%20%225px%22;%20div.style.backgroundColor%20=%20%22#ff6600%22;%20div.style.fontSize%20=%20%2282%%22;%20var%20reloadElt%20=%20document.createElement(%22a%22);%20reloadElt.setAttribute(%22href%22,%20%22javascript:document.hn_reload()%22);%20reloadElt.innerHTML%20=%20%22reload%22;%20div.appendChild(reloadElt);%20sep();%20var%20byParent%20=%20document.createElement(%22a%22);%20byParent.setAttribute(%22href%22,%20%22javascript:document.hn_byNewest(%27parent%27)%22);%20byParent.setAttribute(%22title%22,%20%22Sort%20by%20thread%20parent%22);%20byParent.innerHTML%20=%20%22byParent%22;%20div.appendChild(byParent);%20sep();%20var%20byReply%20=%20document.createElement(%22a%22);%20byReply.setAttribute(%22href%22,%20%22javascript:document.hn_byNewest(%27reply%27)%22);%20byReply.innerHTML%20=%20%22byReply%22;%20byReply.setAttribute(%22title%22,%20%22Sort%20by%20latest%20reply%20in%20thread%22);%20div.appendChild(byReply);%20sep();%20var%20rSpan%20=%20document.createElement(%22span%22);%20rSpan.style.color%20=%20(gReplies==0)%20?%20%27black%27%20:%20%27white%27;%20rSpan.innerHTML%20=%20gReplies%20+%20((gReplies==1)%20?%20%22%20reply%22%20:%20%22%20replies%22);%20div.appendChild(rSpan);%20document.body.appendChild(div);%20}%20function%20me()%20{%20var%20span%20=%20document.getElementsByTagName(%22span%22);%20for%20(var%20i=0;%20i&lt;span.length;%20i++)%20{%20var%20attrs%20=%20span[i].attributes;%20if%20(attrs.length%20==%201%20&amp;&amp;%20attrs[0].name%20==%20%22class%22%20&amp;&amp;%20attrs[0].value%20==%20%22pagetop%22)%20{%20var%20a%20=%20span[i].getElementsByTagName(%22a%22);%20if%20(a.length%20!=%202)%20continue;%20if%20(a[1].innerHTML%20==%20%22logout%22)%20return%20a[0].innerHTML;%20}%20}%20return%20null;%20}%20function%20byNewest(x)%20{%20for%20(var%20i=0;%20i&lt;gParent.childNodes.length;%20i++)%20gParent.removeChild(gParent.childNodes[i]);%20var%20cmp%20=%20function(x,%20y)%20{%20if%20(x%20&lt;%20y)%20return%20-1;%20else%20if%20(x%20&gt;%20y)%20return%201;%20else%20return%200;%20};%20var%20newestParent%20=%20function(x,%20y)%20{%20return%20cmp(x.secs,%20y.secs);%20};%20var%20newestReply%20=%20function(x,%20y)%20{%20return%20cmp(x.latest(),%20y.latest());%20};%20var%20fn%20=%20(x==%27parent%27)%20?%20newestParent%20:%20newestReply;%20gTree.sort(fn);%20for%20(var%20i=0;%20i&lt;gTree.length;%20i++)%20{%20var%20a%20=%20gTree[i].as_array();%20for%20(var%20j=0;%20j&lt;a.length;%20j++)%20gParent.appendChild(a[j].ancestor);%20}%20}%20function%20articleInfo(x)%20{%20try%20{%20if%20(!x)%20x%20=%20document.body.textContent;%20var%20points%20=%20/(\d+)\s*points?/.exec(x);%20var%20timespec%20=%20/(\d+)\s*(day|hour|minute)s?\s*ago/.exec(x);%20var%20ncomments%20=%20/(\d+)\s*comments?/.exec(x);%20return%20[points[0],%20timespec[0],%20ncomments[0],%20ncomments[1]];%20}%20catch(err)%20{%20}%20return%20null;%20}%20function%20updateArticleInfo(old,%20cur)%20{%20try%20{%20var%20points%20=%20cur[0];%20var%20timespec%20=%20cur[1];%20var%20comments%20=%20cur[2];%20var%20n%20=%20parseInt(cur[3])%20-%20parseInt(old[3]);%20var%20td%20=%20document.getElementsByTagName(%22td%22);%20for%20(var%20i=0;%20i&lt;td.length;%20i++)%20{%20var%20e%20=%20td[i];%20if%20(e.attributes.length%20==%201%20&amp;&amp;%20e.attributes[0].name%20==%20%22class%22%20&amp;&amp;%20e.attributes[0].value%20==%20%22subtext%22)%20{%20var%20html%20=%20e.innerHTML;%20html%20=%20html.replace(/(\d+)\s*points?/,%20points);%20html%20=%20html.replace(/\(\d+%20new\)/,%20%22%22);%20html%20=%20html.replace(/(\d+)\s*comments?/,%20comments%20+%20%22%20(%22%20+%20n%20+%20%22%20new)%22);%20html%20=%20html.replace(/(\d+)\s*(day|hour|minute)s?\s*ago/,%20timespec);%20e.innerHTML%20=%20html;%20break;%20}%20}%20}%20catch(err)%20{%20}%20}%20function%20reload()%20{%20document.hn_isReload%20=%20true;%20var%20old%20=%20articleInfo();%20var%20top%20=%20gParent.parentNode;%20top.removeChild(gParent);%20var%20xh%20=%20window.XMLHttpRequest%20?%20new%20window.XMLHttpRequest()%20:%20new%20ActiveXObject(%27Microsoft.XMLHTTP%27);%20xh.onreadystatechange%20=%20function()%20{%20if%20(xh.readyState%20==%204)%20{%20if%20(xh.status%20==%20200)%20{%20try%20{%20var%20html%20=%20xh.responseText;%20html%20=%20html.replace(/[\s\S]*&lt;body&gt;/,%20%22%22);%20html%20=%20html.replace(%20/&lt;img%20src=%22http:\/\/ycombinator.com\/images\/s.gif%22%20height=10%20width=0&gt;[\s\S]*/,%20%22%22);%20html%20=%20html.replace(/[\s\S]*&lt;\/form&gt;/,%20%22%22);%20html%20=%20html.replace(%22&lt;/td&gt;%22,%20%22%22);%20html%20=%20html.replace(%22&lt;/tr&gt;%22,%20%22%22);%20html%20=%20html.replace(%22&lt;/table&gt;%22,%20%22%22);%20html%20=%20html.replace(%22&lt;br&gt;%22,%20%22%22);%20html%20=%20html.replace(%22&lt;br&gt;%22,%20%22%22);%20html%20=%20html.replace(/&lt;br&gt;&lt;br&gt;\n&lt;\/td&gt;&lt;\/tr&gt;&lt;tr&gt;&lt;td&gt;\s*$/,%20%22%22);%20top.innerHTML%20=%20html;%20gParent%20=%20null;%20parse();%20updateArticleInfo(old,%20articleInfo(xh.responseText));%20}%20catch(err)%20{%20alert(%22oops!\nsomething%20went%20wrong%20after%20fetching%20the%20new%20page%22);%20}%20}%20else%20{%20alert(%22reload%20error,%20status%20%22%20+%20xh.status%20+%20%22:\n%22%20+%20xh.responseText);%20}%20}%20};%20xh.open(%22GET%22,%20document.location.href,%20true);%20xh.send(null);%20}%20function%20parse()%20{%20gReplies%20=%200;%20var%20isMe%20=%20me();%20var%20comments%20=%20[];%20var%20tree%20=%20[];%20var%20tr%20=%20document.getElementsByTagName(%22tr%22);%20for%20(var%20i=0;%20i&lt;tr.length;%20i++)%20{%20var%20e%20=%20tr[i];%20var%20c%20=%20e.getElementsByTagName(%27td%27);%20if%20(c.length%20!=%203)%20continue;%20var%20c0%20=%20c[0];%20var%20c1%20=%20c[1];%20var%20c2%20=%20c[2];%20if%20(c1.attributes.length%20!=%201%20||%20c1.attributes[0].name%20!=%20%22valign%22%20||%20c1.attributes[0].value%20!=%20%22top%22)%20continue;%20if%20(c2.attributes.length%20!=%201%20||%20c2.attributes[0].name%20!=%20%22class%22%20||%20c2.attributes[0].value%20!=%20%22default%22)%20continue;%20var%20m%20=%20COMMENT_RE.exec(c2.textContent);%20if%20(!m)%20{%20/*%20no%20match%20means%20deleted%20comment%20*/%20m%20=%20[null,%20%270%27,%20%27%27,%20%270%27,%20%27%27];%20}%20if%20(!gParent)%20{%20gParent%20=%20e.parentNode.parentNode.parentNode.parentNode.parentNode;%20}%20var%20com%20=%20new%20Comment();%20com.elt%20=%20e;%20com.ancestor%20=%20e.parentNode.parentNode.parentNode.parentNode;%20com.level%20=%20c0.getElementsByTagName(%27img%27)[0].width/40;%20com.points%20=%20parseInt(m[1]);%20com.user%20=%20m[2];%20if%20(m[0])%20com.txt%20=%20com.user%20+%20%22%20%22%20+%20e.textContent.replace(m[0],%20%22%22);%20if%20(document.hn_isReload%20&amp;&amp;%20!gOldComments[com.txt])%20markNew(c2);%20else%20unmarkOld(c2);%20gOldComments[com.txt]%20=%20true;%20com.secs%20=%20parseInt(m[3]);%20if%20(/minute/.test(m[4]))%20com.secs%20*=%2060;%20else%20if%20(/hour/.test(m[4]))%20com.secs%20*=%203600;%20else%20if%20(/day/.test(m[4]))%20com.secs%20*=%2086400;%20var%20parent%20=%20findParent(comments,%20com.level);%20if%20(parent)%20{%20if%20(parent.user%20==%20isMe%20&amp;&amp;%20com.user%20!=%20isMe)%20{%20gReplies++;%20markReply(c2);%20}%20parent.children.push(com);%20}%20else%20{%20tree.push(com);%20}%20comments.push(com);%20}%20gComments%20=%20comments;%20gTree%20=%20tree;%20}%20function%20main()%20{%20try%20{%20document.hn_byNewest%20=%20byNewest;%20document.hn_reload%20=%20reload;%20parse();%20gui();%20}%20catch%20(err)%20{%20alert(%22oops!\n%22%20+%20err);%20}%20}%20main();%20})();"&gt;hn.js&lt;/a&gt;
&lt;br/&gt;&lt;br/&gt;
Here it is under bitbucket: &lt;a href="http://bitbucket.org/sri/hnjs/"&gt;hnjs&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;

Sorting restructures the DOM. Only the reload function hits the server. Of course any changes to the HTML will break this badly.
I've tested this with FF 3.5 &amp; Safari 4 under OS X. And under latest Chrome in WinXP.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7123103430063895615?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7123103430063895615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7123103430063895615'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/09/hacker-news-bookmarklet.html' title='Hacker News bookmarklet'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4924301070744014942</id><published>2009-08-08T17:51:00.004-07:00</published><updated>2009-08-08T18:00:13.947-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>37signals on business &amp; software</title><content type='html'>Lately I've been enjoying these videos by &lt;a href="http://37signals.com"&gt;37signals&lt;/a&gt;: &lt;a href="http://37signals.com/speaks"&gt;37signals.speaks&lt;/a&gt;. So refreshing to see these guys talk about business and what makes good software.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4924301070744014942?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4924301070744014942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4924301070744014942'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/08/videos.html' title='37signals on business &amp; software'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-1498384610011676456</id><published>2009-07-06T23:09:00.002-07:00</published><updated>2009-07-06T23:17:04.318-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='notes'/><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Numbers everyone should know</title><content type='html'>Numbers everyone should know from &lt;a href="http://research.google.com/people/jeff/index.html"&gt;Jeff Dean&lt;/a&gt;'s &lt;a href="http://cs343-spr0607.stanford.edu/materials/jeff_dean/"&gt;talk at Stanford&lt;/a&gt;:

&lt;pre class="codebox"&gt;
L1 cache reference 0.5 ns
Branch mispredict 5 ns
L2 cache reference 7 ns
Mutex lock/unlock 100 ns
Main memory reference 100 ns
Compress 1K bytes with Zippy 10,000 ns
Send 2K bytes over 1 Gbps network 20,000 ns [.02 ms]
Read 1 MB sequentially from memory 250,000 ns
Round trip within same datacenter 500,000 ns
Disk seek 10,000,000 ns
Read 1 MB sequentially from network 10,000,000 ns [10 ms]
Read 1 MB sequentially from disk 30,000,000 ns
Send packet CA to Netherlands to CA 150,000,000 ns
&lt;/pre&gt;

From Cuong Do's &lt;a href="http://video.google.com/videoplay?docid=-6304964351441328559"&gt;Youtube Scalability talk&lt;/a&gt;:
&lt;pre class="codebox"&gt;
Page rendering time: keep less than 100 ms
&lt;/pre&gt;

There are also some interesting number on Wikipedia's &lt;a href="http://en.wikipedia.org/wiki/Google_platform"&gt;Google platform page&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-1498384610011676456?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1498384610011676456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1498384610011676456'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/07/numbers-everyone-should-know.html' title='Numbers everyone should know'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7126949588316513263</id><published>2009-05-24T17:15:00.001-07:00</published><updated>2009-05-24T17:18:07.769-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>from Getting Real, the book</title><content type='html'>From &lt;a href="http://gettingreal.37signals.com/ch05_It_Just_Doesnt_Matter.php"&gt;Getting Real&lt;/a&gt; the amazing book by &lt;a href="http://www.37signals.com/"&gt;37signals&lt;/a&gt;:


&lt;blockquote&gt;The best designers and the best programmers aren’t the ones
with the best skills, or the nimblest ﬁngers, or the ones who can
rock and roll with Photoshop or their environment of choice,
they are the ones that can determine what just doesn’t matter.
That’s where the real gains are made. &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7126949588316513263?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7126949588316513263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7126949588316513263'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/05/from-getting-real-book.html' title='from Getting Real, the book'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4633984874187869458</id><published>2009-05-22T19:47:00.003-07:00</published><updated>2009-05-22T19:48:59.991-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Ruby Object Model</title><content type='html'>&lt;p&gt;These are my notes from &lt;a href="http://pragdave.blogs.pragprog.com/pragdave/"&gt;Dave Thomas&lt;/a&gt;'s &lt;a href="http://www.engineyard.com/blog/community/scotland-on-rails/page-2/"&gt;Ruby Object Model&lt;/a&gt;.

&lt;pre class="codebox"&gt;
# Ruby Object Model
# http://www.engineyard.com/blog/community/scotland-on-rails/page-2/

# everything is an object
# object is a class
# class is an object

# self:
#  - current object
#  - where instance vars are found
#  - default receiver for methods calls

# changes in self changes ruby's view of the universe
# by: methods calls &amp;amp; class/module definitions

animal = "cat"
puts animal.upcase

# find animal object -&amp;gt; find table of methods -&amp;gt; call method
# class =&amp;gt; object that has a table of methods
# every single method call works exactly the same way

puts animal.object_id
# if can't methods in 1st table =&amp;gt; goes to parent 
# (superclass of the object)

# Object toplevel in Ruby 1.8, BasicObject in Ruby 1.9
# If no matching methods found in ruby, you are back
# to original object and look for method_missing method.

def animal.speak
  puts "meaow"
end

animal.speak

# --- SELF changes on method call

# Method lookup -&amp;gt; one right and one up
# So the above object instance method sits 
# one to the right of that particular object.
# So a newly created class just for the animal
# object is anonymous. But when asked what class
# the above object belongs to, it says string,
# and not the newly created anonymous class.
# AKA, singleton class or metaclasss or eigenclass
# How is the animal.speak method defined?
# (1) Ruby sets "self" to the cat string object -- self
#     set to the receiver
# (2) Looks for the method in the method table associated
#     with that object (look in self's class for the object)
# (3) If not found, scan for method_missing
# (4) Eventually find some method &amp;amp; invoke it &amp;amp; when done,
#     restores original value of self.
#
# If a method call in Ruby doesn't have an explicit
# receiver -- then Ruby doesn't reset self -- self
# stays the same &amp;amp; no need to pop back at the end.

# So the method "puts" is a private method in Object (actually
# in Kernel), so you can only call it with an implicit receiver,
# not an explicit one.

class String
  puts "in string"
end

begin
  "hi".puts
rescue NoMethodError
  puts "puts is private"
end

# In Ruby class definitions are executable code.
puts "===class defn"
puts "toplevel #{self}"
class &amp;lt;&amp;lt; self
  puts "class &amp;lt;&amp;lt; self's #{self}"
end
class A
  puts "class A's #{self}"
end
module B
  puts "module B's #{self}"
end

# When you define a class like "class A; end",
# Ruby creates a brand new class and assigns that
# to the constant A.

# When excuting a class or module definition, self
# is set to the class or module object. Why? You can
# do "def self.a" for class methods (or old school
# ruby programmers using "def A.a"); But ruby doesn't
# have class methods (or static methods), all methods
# are the same. These methods are just defined on the class.
# It inserts a singleton class on that particular class object.

# To do metaprogramming in Ruby:
# - Instance variables are looked up in self
# - Methods are looked up in self's class

# these 2 are the same:
def animal.do
  puts "doing"
end
# "class &amp;lt;&amp;lt; animal" means open up the singleton class of this object
# self is set to that singleton class
class &amp;lt;&amp;lt; animal
  puts "class &amp;lt;&amp;lt; animal: #{self}"
  def do
    puts "doing"
  end
end

class N
  # opening up the meta/singleton class and dumping all the
  # methods defined there
  class &amp;lt;&amp;lt; self
    # class methods
  end
end

# This doesn't work
class F
  @a = 10 # self is class object
  def f
    @a # self is the instance 
  end
  def F.f # this work
    @a
  end
  
  class &amp;lt;&amp;lt; self # this also works
    attr_accessor :f
  end
  
end

class Y; end
class Z &amp;lt; Y; end
# the Y in "Z &amp;lt; Y" is an expression
wxyz = Y
class Z &amp;lt; wxyz; end # same as above

a = Struct.new(:a, :b, :c) # creates a class object on the fly
puts a.new(1,2,3) 
# Struct is just a data holder

class T &amp;lt; Struct.new(:a, :b)
end

# include Module in a class, then invoke the instance methods
# of the module with class as the receiver
# It doesn't add the methods; any instance methods define
# in class overrides the module methods, even if it is included
# after the method definition.

module M
  def speak; puts :no; end
end

class AM
  def speak; puts :ok;  end
  include M
end

am = AM.new.speak

# include =&amp;gt; singleton as immediate parent of my class
# and its methods are methods of my module

# hierarchy =&amp;gt; singleton, class, module
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4633984874187869458?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4633984874187869458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4633984874187869458'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/05/ruby-object-mode.html' title='Ruby Object Model'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-6911477767384502339</id><published>2009-04-18T15:20:00.003-07:00</published><updated>2009-04-18T15:23:53.882-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Notes from Alex Martelli's talk @ Pycon 2009</title><content type='html'>My notes from &lt;a href="http://www.aleax.it/"&gt;Alex Martelli&lt;/a&gt;'s talk @ &lt;a href="http://pycon.blip.tv/"&gt;Pycon 2009&lt;/a&gt;: &lt;a href="http://pycon.blip.tv/file/1957071/"&gt;video here&lt;/a&gt;.

&lt;pre style="background-color:white;border:0"&gt;
http://pycon.blip.tv/file/1957071/
watched on April 18, 2009
abstraction as leverage
by alex martelli
========================
abstraction is something you can't avoid
abstraction is leverage - by working at the higher level
 you can do a lot with so little (layers &amp; layers)
leverage can crush you if things go wrong
so if you need care to USE abstraction,
 you need double layer of care to PRODUCE abstraction
all abstraction's leak (spolsky's law) -- where you must
 get to some of the level below
often you sometimes want abstractions to leak!
(like distributed filesystems)
abstractions can slow you down -- latest research:
 "to abstract is to procrastinate"; more abstract
 the "todo" is, the more the students will procrastinate
things way in past are more abstracted that more
 recent ones
to achieve, think Concrete: what's the next 1 thing,
 i'm going to do
interaction design: "Joe Blow" vs "the user"
37signals: prefer action over abstraction
all abstraction leak because: "the map is not
 the territory"; before you can abstract,
 you must see the details; before you can withdraw,
 you must stand close; abstract only you know
 all the details (which won't be possible), so
 be flexible and humble!
TCP/IP abstraction leak: designed in an era when
everyone was friendly
Need to understand several layers below and above
(Filesystem: below layers =&gt; device drivers,
 above layers =&gt; how are other programmers consume
 the apis)
Knuth: programmer is mostly to shift levels of
abstraction from low to high; see things simutaneously
at both low &amp; high level
Jason Fried: copying skips understanding;
understanding is how you grow; you have to understand
why something works or why something is how it is;
when you copy you miss that; (You just copy the high
level abstractions blindly)
Jeff Atwood: don't reinvent the wheel unless you plan
of learning more abt wheels
Bottleneck -- if you remove it you have a glass!
Google App engine -- counting how many reads &amp; writes
Find bottleneck (where everything must go thru) and
monkey patch that; problamatic
App Engine provide hooks to do same thing!
(Q&amp;A: answer: focus on making things easier
 to recover when they break, instead of trying
 to protect everything)

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-6911477767384502339?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6911477767384502339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6911477767384502339'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/04/notes-from-alex-martellis-talk-pycon.html' title='Notes from Alex Martelli&apos;s talk @ Pycon 2009'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-5321027413773315749</id><published>2009-04-10T12:33:00.003-07:00</published><updated>2009-04-10T12:41:27.604-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Mercurial &amp; bitbucket</title><content type='html'>&lt;p&gt;I'm starting to use &lt;a href="http://www.selenic.com/mercurial/wiki/"&gt;Mercurial&lt;/a&gt; for version control and I really like it. Also, I got a &lt;a href="http://bitbucket.org/"&gt;bitbucket.org&lt;/a&gt; account: &lt;a href="http://bitbucket.org/sri/"&gt;sri&lt;/a&gt; and put up my first project there: &lt;a href="http://bitbucket.org/sri/ccspendings/"&gt;ccspendings&lt;/a&gt;, a very simple program that tell you where you spend your credit card money (currently supports Juniper credit card). It'll generate some useful charts using the &lt;a href="http://code.google.com/apis/chart/"&gt;Google Charts API&lt;/a&gt;. Here is an example of how much I spend on Gas:
&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_O2rCstTaSIQ/Sd-gks7zMeI/AAAAAAAAA7c/1L-yzSWszd8/s1600-h/gas-example.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 320px;" src="http://3.bp.blogspot.com/_O2rCstTaSIQ/Sd-gks7zMeI/AAAAAAAAA7c/1L-yzSWszd8/s400/gas-example.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323149836972929506" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-5321027413773315749?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/5321027413773315749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/5321027413773315749'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/04/mercurial-bitbucket.html' title='Mercurial &amp; bitbucket'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_O2rCstTaSIQ/Sd-gks7zMeI/AAAAAAAAA7c/1L-yzSWszd8/s72-c/gas-example.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-1610474913521642670</id><published>2009-04-06T16:47:00.004-07:00</published><updated>2009-04-06T16:50:45.764-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Guido van Rossum Python Quote</title><content type='html'>At the very end of &lt;a href="http://mail.python.org/replybot/webmaster.txt"&gt;Python.Org's Webmaster mailing list's auto-reply text&lt;/a&gt;, a quote by Guido van Rossum on how to code in Python:
&lt;br/&gt;
&lt;blockquote&gt;
The joy of coding Python should be in seeing short, concise, readable&lt;br/&gt;
classes that express a lot of action in a small amount of clear code -- &lt;br/&gt;
not in reams of trivial code that bores the reader to death.
&lt;br/&gt;
--GvR
&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-1610474913521642670?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1610474913521642670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1610474913521642670'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/04/guido-van-rossum-python-quote.html' title='Guido van Rossum Python Quote'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4578035594285128142</id><published>2009-02-19T23:16:00.003-07:00</published><updated>2009-02-19T23:32:22.054-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Greasemonkey Search helper</title><content type='html'>&lt;p&gt; 
Here is a handy &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/748"&gt;Greasemonkey&lt;/a&gt; script: it allows you to search for the selected text in a background tab. This is useful because it won't distract from what you reading right now. And you have different keys are associated with different searches....
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Alt-A&lt;/span&gt; - searches Amazon.com&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Alt-G&lt;/span&gt; - search Google.com&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Alt-W&lt;/span&gt; - searches Wikipedia.org&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Alt-Y&lt;/span&gt; - searches YouTube.com&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Alt-N&lt;/span&gt; - searches GoogleNews.com&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Alt-R&lt;/span&gt; - searches RottenTomatoes.com&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;pre class="codebox"&gt;
// ==UserScript==
// @name           Sri's Stuff
// @namespace      http://defcraft.org
// @description    Sri's Stuff
// @include        *
// ==/UserScript==

// Created-On: Jun 28, 2007
// Description:
//
// o Selection Search:
//   Make a selection and hit "G" or "A" to
//   search either Google or Amazon. Search opens
//   in background Tab.


(function () {
    
  function kpHandler(event) {
    var letter = String.fromCharCode(event.charCode);
    var sel = document.getSelection();

    if (!event.altKey || sel.length == 0)
      return;

    switch (letter) {
    case "a": case "Ã¥": // Alt-A
      doAmazonSearch(sel); 
      break;

    case "g": case "Â©": // Alt-G
      doGoogleSearch(sel);
      break;
      
    case "w": case "âˆ‘": // Alt-W
      doWikipediaSearch(sel);
      break;
      
    case "Â¥": // Alt-Y
      doYoutubeSearch(sel);
      break;
      
    case "Ëœ": // Alt-N
      doGoogleNewsSearch(sel);
      break;
      
    case "Â®": // Alt-R
      doRottenTomatoesSearch(sel);
      break;
    }
  }


  // == User actions ============================
  
  function doRottenTomatoesSearch(sel) {
    var url = "http://www.rottentomatoes.com/" + 
              encodeURIComponent(sel);
    GM_openInTab(url);
  }
  
  function doGoogleNewsSearch(sel) {
    var url = "http://news.google.com/news?hl=en&amp;amp;ned=&amp;amp;q=" + 
              encodeURIComponent(sel) +
              "&amp;amp;btnG=Search+News";
    GM_openInTab(url);
  }
  
  function doYoutubeSearch(sel) {
    var url = "http://www.youtube.com/results?search_type=&amp;amp;search_query=" + 
              encodeURIComponent(sel) + "&amp;amp;aq=f";
    GM_openInTab(url);
  }
  
  function doWikipediaSearch(sel) {
    var url = "http://en.wikipedia.org/wiki/Special:Search?search=" +
              encodeURIComponent(sel) + "&amp;amp;sourceid=Mozilla-search";

    GM_openInTab(url);
  }

  function doAmazonSearch(sel) {
    var url = 'http://www.amazon.com/exec/obidos/external-search/' + 
              '?field-keywords=' + encodeURIComponent(sel) +
              '&amp;amp;mode=blended&amp;amp;tag=mozilla-20&amp;amp;sourceid=Mozilla-search';

    GM_openInTab(url);
  }


  function doGoogleSearch(sel) {
    var url = 'http://www.google.com/search?q=' +
              encodeURIComponent(sel) +
              '&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;aq=t' +
              '&amp;amp;rls=org.mozilla:en-US:official&amp;amp;client=firefox-a';

    GM_openInTab(url);
  }

  document.addEventListener('keypress',  kpHandler, false);

})();

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4578035594285128142?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4578035594285128142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4578035594285128142'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/02/greasemonkey-search-helper.html' title='Greasemonkey Search helper'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-2866182111592904149</id><published>2009-01-31T00:35:00.001-07:00</published><updated>2009-01-31T01:41:34.067-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>palindromic pangram -- the simple way</title><content type='html'>&lt;pre class="codebox"&gt;
# sri, Sun Apr 13 15:05:56 PDT 2008
#
# A simple way to find palindromic pangrams.
# Completes in under 10 secs for the word list given
# by ITA software.
#
# The Algorithm: I find small palindromes (1-word &amp;amp; 2-word
# palindromes) and hook them up together. Example:
# if you have 1-word palindromes: "aa", "bb", &amp;amp; "cc", then
# aabbccccbbaa is a palindrome that contains all the characters
# a, b &amp;amp; c. It, by no means, produces an efficient
# palindrome. It also works for the dict file under OS X.
# So I really didn't need to find out 3-word palindroms,
# which seems much harder....

import string, sys

left = set(string.ascii_lowercase)
words = [x[:-1] for x in open(sys.argv[1]).readlines()]
        # use below for certain dicts that have many 1-letter words
        # if len(x) &amp;gt; 2]
         
wordset = set(words)
result = []
prefix = {}
suffix = {}

for word in words:
    for i in xrange(len(word)):
        pre = word[:i+1]
        if pre not in prefix:
            prefix[pre] = []
        prefix[pre].append(word)
        suf = word[-(i+1):]
        if suf not in suffix:
            suffix[suf] = []
        suffix[suf].append(word)  

def ispal(s):
    i = 0
    j = len(s)-1
    while i &amp;lt; j:
        if s[i] != s[j]:
            return False
        i += 1
        j -= 1
    return True

def words_containing(words, chars):
    for word in words:
        if any(c in word for c in chars):
            yield word

def markpal(*words):
    result.append(' '.join(words))
    for c in result[-1]:
        if c in left: left.remove(c)

# THIS IS BROKEN:
def smallest_pal(items):
    def score(x):
        x = x.replace(' ', '')
        uniques = len(set(x))
        return int(100 * uniques / len(x))
    items = sorted(items, key=score, reverse=True)
    left = set(string.ascii_lowercase)
    result = []
    for item in items:
        if not any(c in item for c in left):
            continue
        result.append(item)
        for c in item:
            if c in left: left.remove(c)
            
    print 'shortest pal:', 2 * len(''.join(result).replace(' ', ''))
    print '|'.join(result)
    print '|'.join(reversed(result))


# we don't care abt making the palindrome small
# we'll try do that later
for word in words:
    if ispal(word): markpal(word)
print 'left over from 1-word pals:', left

# figuring out 2-word palindromes is very simple;
# try to "mirror" the characters on both sides
# and 1-st test if its forms a palindrome and
# then check to see if its in the word list
for word in words_containing(words, left):
    for i in xrange(len(word)):
        pre = ''.join(reversed(word[-(i+1):]))
        #if ispal(pre+word) and prefix.has_key(pre): BUG!
        if ispal(pre+word) and pre in wordset:
            markpal(pre, word)
        suf = ''.join(reversed(word[:i+1]))
        #if ispal(word+suf) and suffix.has_key(suf): BUG!
        if ispal(word+suf) and suf in wordset:
            markpal(word, suf)
if not left:
    # print things out nicely so i can quickly check result visually
    print 'found palindromic pangram:', 2*sum(len(x) for x in result)
    output = []
    for c in string.ascii_lowercase:
        for word in result:
            if c in word:
                output.append((c, word))
                break
    for (c, w) in output:
        print "[%s] %s" % (c, w)
    #smallest_pal(result)
else:
    print 'no solution found'


&lt;/pre&gt;
&lt;br/&gt;
&lt;span style="font-size:68%"&gt;
left over from 1-word pals: set(['j', 'q', 'z'])&lt;br/&gt;
found palindromic pangram: 914&lt;br/&gt;
[a] aa&lt;br/&gt;
[b] aba&lt;br/&gt;
[c] civic&lt;br/&gt;
[d] dad&lt;br/&gt;
[e] deed&lt;br/&gt;
[f] deified&lt;br/&gt;
[g] aga&lt;br/&gt;
[h] aha&lt;br/&gt;
[i] bib&lt;br/&gt;
[j] raj ajar&lt;br/&gt;
[k] deked&lt;br/&gt;
[l] ala&lt;br/&gt;
[m] ama&lt;br/&gt;
[n] ana&lt;br/&gt;
[o] bob&lt;br/&gt;
[p] pap&lt;br/&gt;
[q] ta qat&lt;br/&gt;
[r] ere&lt;br/&gt;
[s] sagas&lt;br/&gt;
[t] otto&lt;br/&gt;
[u] alula&lt;br/&gt;
[v] ava&lt;br/&gt;
[w] awa&lt;br/&gt;
[x] oxo&lt;br/&gt;
[y] eye&lt;br/&gt;
[z] feeze ef&lt;br/&gt;
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-2866182111592904149?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2866182111592904149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2866182111592904149'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/01/palindromic-pangram-simple-way.html' title='palindromic pangram -- the simple way'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7496184204883835712</id><published>2009-01-27T10:46:00.001-07:00</published><updated>2009-01-27T11:50:15.054-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>ITA software -- Sling Blade Runner</title><content type='html'>&lt;p&gt;The Puzzle by &lt;a href="http://www.itasoftware.com/careers/puzzle_archive.html"&gt;ITA Software&lt;/a&gt;:
&lt;/p&gt;
&lt;pre class="codebox"&gt;
How long a chain of overlapping movie titles, like Sling Blade Runner, can you find?
&lt;/pre&gt;
&lt;p&gt;And the date is a list of movie titles provided by &lt;a href="http://www.movielens.umn.edu/"&gt;movielens&lt;/a&gt;.
And here is my solution with the resulting output:&lt;/p&gt;

&lt;pre class="codebox"&gt;
import collections, time

starttime = time.time()
titles = [x.strip() for x in open('MOVIES.LST.txt') if x.strip()]

# Add titles to beginnings such that, beginnings[T] = list of titles
# that start with some suffix of title T.
beginnings = collections.defaultdict(list)
ends = collections.defaultdict(list)
begs = collections.defaultdict(list)
for t in titles:
    s = t.split()
    for i in range(len(s) - 1):
        end = ' '.join(s[-i-1:])
        ends[end].append(t)
        beg = ' '.join(s[:i+1])
        begs[beg].append(t)
for k in [k for k in ends if k in begs]:
    for t in ends[k]:
        beginnings[t].extend( begs[k] )

titles.sort(key=lambda t: len(beginnings[t]), reverse=True)
for t in beginnings.keys():
    # if reverse is set to False, then the longer results don't
    # show up that quickly. 
    beginnings[t].sort(key=lambda t: len(beginnings[t]), reverse=True)

best = []
try:
    for t in titles:
        states = collections.deque()
        states.append( (set([t]), [t]) )
        while states:
            seen, state = states.popleft()
            last = state[-1]
            for x in beginnings[last]: # remember beginnings is a defaultdict
                if x in seen:
                    continue
                seen2 = seen.copy()
                seen2.add(x)
                newstate = (seen2, state + [x])
                states.appendleft(newstate) # KEY!!
                if len(newstate[1]) &amp;gt; len(best):
                    best = newstate[1]
except KeyboardInterrupt:
    print

print '\n'.join(best)
print '--'
print len(best)
print 'elapsed secs', time.time()-starttime

&lt;/pre&gt;

&lt;span style="font-size:68%"&gt;
Q AND A&lt;br/&gt;
A KISS BEFORE DYING&lt;br/&gt;
DYING YOUNG&lt;br/&gt;
YOUNG GUNS&lt;br/&gt;
GUNS OF THE MAGNIFICENT SEVEN&lt;br/&gt;
SEVEN YEARS IN TIBET&lt;br/&gt;
TIBET CRY OF THE SNOW LION&lt;br/&gt;
LION OF THE DESERT&lt;br/&gt;
DESERT HEARTS&lt;br/&gt;
HEARTS OF DARKNESS A FILMMAKERS APOCALYPSE&lt;br/&gt;
APOCALYPSE NOW&lt;br/&gt;
NOW YOU SEE HIM NOW YOU DONT&lt;br/&gt;
DONT BOTHER TO KNOCK&lt;br/&gt;
KNOCK OFF&lt;br/&gt;
OFF THE MAP&lt;br/&gt;
MAP OF THE HUMAN HEART&lt;br/&gt;
HEART CONDITION&lt;br/&gt;
CONDITION RED&lt;br/&gt;
RED RIVER&lt;br/&gt;
RIVER OF NO RETURN&lt;br/&gt;
RETURN OF THE FLY&lt;br/&gt;
FLY AWAY HOME&lt;br/&gt;
HOME ALONE&lt;br/&gt;
ALONE IN THE DARK&lt;br/&gt;
DARK BLUE WORLD&lt;br/&gt;
WORLD TRADE CENTER&lt;br/&gt;
CENTER STAGE&lt;br/&gt;
STAGE FRIGHT&lt;br/&gt;
FRIGHT NIGHT&lt;br/&gt;
NIGHT FALLS ON MANHATTAN&lt;br/&gt;
MANHATTAN MURDER MYSTERY&lt;br/&gt;
MYSTERY ALASKA&lt;br/&gt;
ALASKA SPIRIT OF THE WILD&lt;br/&gt;
WILD IN THE STREETS&lt;br/&gt;
STREETS OF FIRE&lt;br/&gt;
FIRE ON THE MOUNTAIN&lt;br/&gt;
THE MOUNTAIN MEN&lt;br/&gt;
MEN CRY BULLETS&lt;br/&gt;
BULLETS OVER BROADWAY&lt;br/&gt;
BROADWAY DANNY ROSE&lt;br/&gt;
ROSE RED&lt;br/&gt;
RED HEAT&lt;br/&gt;
HEAT AND DUST&lt;br/&gt;
DUST TO GLORY&lt;br/&gt;
GLORY ROAD&lt;br/&gt;
ROAD GAMES&lt;br/&gt;
GAMES PEOPLE PLAY NEW YORK&lt;br/&gt;
NEW YORK COP&lt;br/&gt;
COP LAND&lt;br/&gt;
LAND OF THE DEAD&lt;br/&gt;
DEAD MAN ON CAMPUS&lt;br/&gt;
CAMPUS MAN&lt;br/&gt;
MAN TROUBLE&lt;br/&gt;
TROUBLE EVERY DAY&lt;br/&gt;
DAY OF THE WOMAN&lt;br/&gt;
WOMAN ON TOP&lt;br/&gt;
TOP GUN&lt;br/&gt;
GUN CRAZY&lt;br/&gt;
CRAZY PEOPLE&lt;br/&gt;
PEOPLE WILL TALK&lt;br/&gt;
TALK RADIO&lt;br/&gt;
RADIO DAYS&lt;br/&gt;
DAYS OF HEAVEN&lt;br/&gt;
HEAVEN CAN WAIT&lt;br/&gt;
WAIT UNTIL DARK&lt;br/&gt;
DARK CITY&lt;br/&gt;
CITY OF JOY&lt;br/&gt;
JOY RIDE&lt;br/&gt;
RIDE THE HIGH COUNTRY&lt;br/&gt;
COUNTRY LIFE&lt;br/&gt;
LIFE WITH FATHER&lt;br/&gt;
FATHER OF THE BRIDE&lt;br/&gt;
BRIDE OF THE WIND&lt;br/&gt;
THE WIND AND THE LION&lt;br/&gt;
THE LION KING&lt;br/&gt;
KING RAT&lt;br/&gt;
RAT RACE&lt;br/&gt;
RACE WITH THE DEVIL&lt;br/&gt;
THE DEVIL RIDES OUT&lt;br/&gt;
OUT TO SEA&lt;br/&gt;
SEA OF LOVE&lt;br/&gt;
LOVE AND SEX&lt;br/&gt;
SEX AND THE OTHER MAN&lt;br/&gt;
MAN ON FIRE&lt;br/&gt;
FIRE IN THE SKY&lt;br/&gt;
SKY HIGH&lt;br/&gt;
HIGH SPIRITS&lt;br/&gt;
SPIRITS OF THE DEAD&lt;br/&gt;
DEAD BANG&lt;br/&gt;
BANG BANG YOURE DEAD&lt;br/&gt;
DEAD MAN&lt;br/&gt;
MAN OF THE HOUSE&lt;br/&gt;
HOUSE PARTY&lt;br/&gt;
PARTY MONSTER&lt;br/&gt;
MONSTER IN A BOX&lt;br/&gt;
BOX OF MOON LIGHT&lt;br/&gt;
LIGHT OF DAY&lt;br/&gt;
DAY FOR NIGHT&lt;br/&gt;
NIGHT ON EARTH&lt;br/&gt;
EARTH GIRLS ARE EASY&lt;br/&gt;
EASY MONEY&lt;br/&gt;
MONEY FOR NOTHING&lt;br/&gt;
NOTHING PERSONAL&lt;br/&gt;
PERSONAL BEST&lt;br/&gt;
BEST FRIENDS&lt;br/&gt;
FRIENDS AND LOVERS&lt;br/&gt;
LOVERS AND OTHER STRANGERS&lt;br/&gt;
STRANGERS WHEN WE MEET&lt;br/&gt;
MEET JOE BLACK&lt;br/&gt;
BLACK DOG&lt;br/&gt;
DOG RUN&lt;br/&gt;
RUN SILENT RUN DEEP&lt;br/&gt;
DEEP BLUE&lt;br/&gt;
BLUE STEEL&lt;br/&gt;
STEEL DAWN&lt;br/&gt;
DAWN OF THE DEAD&lt;br/&gt;
DEAD OF NIGHT&lt;br/&gt;
NIGHT MOTHER&lt;br/&gt;
MOTHER NIGHT&lt;br/&gt;
NIGHT AND THE CITY&lt;br/&gt;
CITY OF ANGELS&lt;br/&gt;
ANGELS WITH DIRTY FACES&lt;br/&gt;
FACES OF DEATH 4&lt;br/&gt;
4 LITTLE GIRLS&lt;br/&gt;
GIRLS JUST WANT TO HAVE FUN&lt;br/&gt;
FUN AND FANCY FREE&lt;br/&gt;
FREE WILLY 2 THE ADVENTURE HOME&lt;br/&gt;
HOME ALONE 3&lt;br/&gt;
3 NINJAS KICK BACK&lt;br/&gt;
BACK TO SCHOOL&lt;br/&gt;
SCHOOL OF ROCK&lt;br/&gt;
ROCK N ROLL HIGH SCHOOL&lt;br/&gt;
HIGH SCHOOL HIGH&lt;br/&gt;
HIGH CRIMES&lt;br/&gt;
CRIMES OF PASSION&lt;br/&gt;
PASSION IN THE DESERT&lt;br/&gt;
DESERT BLUE&lt;br/&gt;
BLUE CAR&lt;br/&gt;
CAR 54 WHERE ARE YOU&lt;br/&gt;
YOU CAN COUNT ON ME&lt;br/&gt;
ME WITHOUT YOU&lt;br/&gt;
YOU CANT TAKE IT WITH YOU&lt;br/&gt;
YOU LIGHT UP MY LIFE&lt;br/&gt;
MY LIFE WITHOUT ME&lt;br/&gt;
ME MYSELF I&lt;br/&gt;
I NEVER PROMISED YOU A ROSE GARDEN&lt;br/&gt;
GARDEN STATE&lt;br/&gt;
STATE FAIR&lt;br/&gt;
FAIR GAME&lt;br/&gt;
GAME OF DEATH&lt;br/&gt;
DEATH SHIP&lt;br/&gt;
SHIP OF FOOLS&lt;br/&gt;
FOOLS RUSH IN&lt;br/&gt;
IN PRAISE OF OLDER WOMEN&lt;br/&gt;
WOMEN IN LOVE&lt;br/&gt;
LOVE LIFE&lt;br/&gt;
LIFE OR SOMETHING LIKE IT&lt;br/&gt;
IT HAD TO BE YOU&lt;br/&gt;
YOU ONLY LIVE ONCE&lt;br/&gt;
ONCE AROUND&lt;br/&gt;
AROUND THE BEND&lt;br/&gt;
BEND OF THE RIVER&lt;br/&gt;
THE RIVER WILD&lt;br/&gt;
WILD THINGS&lt;br/&gt;
THINGS TO COME&lt;br/&gt;
COME AND GET IT&lt;br/&gt;
IT HAPPENED ONE NIGHT&lt;br/&gt;
ONE NIGHT STAND&lt;br/&gt;
STAND IN&lt;br/&gt;
IN GODS HANDS&lt;br/&gt;
HANDS ON A HARD BODY&lt;br/&gt;
BODY AND SOUL&lt;br/&gt;
SOUL FOOD&lt;br/&gt;
FOOD OF LOVE&lt;br/&gt;
LOVE WALKED IN&lt;br/&gt;
IN OLD CALIFORNIA&lt;br/&gt;
CALIFORNIA SPLIT&lt;br/&gt;
SPLIT SECOND&lt;br/&gt;
SECOND BEST&lt;br/&gt;
BEST OF THE BEST&lt;br/&gt;
THE BEST OF EVERYTHING&lt;br/&gt;
EVERYTHING RELATIVE&lt;br/&gt;
RELATIVE FEAR&lt;br/&gt;
FEAR X&lt;br/&gt;
X THE MAN WITH THE X RAY EYES&lt;br/&gt;
EYES OF AN ANGEL&lt;br/&gt;
ANGEL BABY&lt;br/&gt;
BABY SECRET OF THE LOST LEGEND&lt;br/&gt;
LEGEND OF THE LOST&lt;br/&gt;
THE LOST BOYS&lt;br/&gt;
BOYS ON THE SIDE&lt;br/&gt;
SIDE OUT&lt;br/&gt;
OUT COLD&lt;br/&gt;
COLD FEVER&lt;br/&gt;
FEVER PITCH&lt;br/&gt;
PITCH BLACK&lt;br/&gt;
BLACK HAWK DOWN&lt;br/&gt;
DOWN WITH LOVE&lt;br/&gt;
LOVE AND DEATH&lt;br/&gt;
DEATH WISH V THE FACE OF DEATH&lt;br/&gt;
DEATH WISH&lt;br/&gt;
WISH UPON A STAR&lt;br/&gt;
STAR TREK THE MOTION PICTURE&lt;br/&gt;
PICTURE BRIDE&lt;br/&gt;
BRIDE OF THE MONSTER&lt;br/&gt;
MONSTER HOUSE&lt;br/&gt;
HOUSE OF DRACULA&lt;br/&gt;
DRACULA DEAD AND LOVING IT&lt;br/&gt;
IT TAKES TWO&lt;br/&gt;
TWO MUCH&lt;br/&gt;
MUCH ADO ABOUT NOTHING&lt;br/&gt;
NOTHING BUT TROUBLE&lt;br/&gt;
TROUBLE IN PARADISE&lt;br/&gt;
PARADISE ROAD&lt;br/&gt;
ROAD HOUSE&lt;br/&gt;
HOUSE OF FRANKENSTEIN&lt;br/&gt;
FRANKENSTEIN AND THE MONSTER FROM HELL&lt;br/&gt;
HELL UP IN HARLEM&lt;br/&gt;
HARLEM RIVER DRIVE&lt;br/&gt;
DRIVE ME CRAZY&lt;br/&gt;
CRAZY AS HELL&lt;br/&gt;
HELL NIGHT&lt;br/&gt;
NIGHT AND DAY&lt;br/&gt;
DAY OF THE DEAD&lt;br/&gt;
THE DEAD GIRL&lt;br/&gt;
GIRL IN THE CADILLAC&lt;br/&gt;
CADILLAC MAN&lt;br/&gt;
MAN OF THE YEAR&lt;br/&gt;
YEAR OF THE DRAGON&lt;br/&gt;
DRAGON SEED&lt;br/&gt;
SEED OF CHUCKY&lt;br/&gt;
----&lt;br/&gt;
231&lt;br/&gt;
elapsed secs 101.631449938&lt;br/&gt;

&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7496184204883835712?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7496184204883835712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7496184204883835712'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/01/ita-software-sling-blade-runner.html' title='ITA software -- Sling Blade Runner'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-8570095747612827345</id><published>2009-01-18T13:12:00.000-07:00</published><updated>2009-01-18T11:37:38.286-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Great Paul Graham quote...</title><content type='html'>Just brilliant:

&lt;blockquote&gt;
So we just finished a new round of optimizations as part of our &lt;span style="font-weight:bold;"&gt;ongoing quest to prove that with sufficient caching you can serve arbitrarily large numbers of requests with arbitrarily slow languages.&lt;/span&gt;
&lt;br/&gt;
-- &lt;a href="http://ycombinator.com/newsnews.html#9jan09"&gt;Paul Graham&lt;/a&gt;, on releasing a new version of &lt;a href="http://news.ycombinator.com/"&gt;Hacker News&lt;/a&gt;
&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-8570095747612827345?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8570095747612827345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8570095747612827345'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/01/great-paul-graham-quote.html' title='Great Paul Graham quote...'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7431574182407822867</id><published>2009-01-16T01:52:00.007-07:00</published><updated>2009-01-16T02:15:48.430-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><title type='text'>Opening Python files (and other source files) "in-browser" in Firefox 3.0+</title><content type='html'>If Firefox keeps annoying you with a Download dialog box, when you drag/drop Python source files into the browser window, do the following: go to your Firefox profiles directory (for Mac OS X, it is under ~/Library/Application Support/Firefox/Profiles/xyz.default), open up the mimeTypes.rdf file and (carefully) delete all references to "x-python". After a restart, things should work fine! Sample junk found in mimeTypes.rdf (there were several of these):


&lt;pre class="codebox"&gt;
  &amp;lt;RDF:Description RDF:about="urn:mimetype:text/x-python"
                   NC:fileExtensions="py"
                   NC:description=""
                   NC:value="text/x-python"
                   NC:editable="true"&amp;gt;
    &amp;lt;NC:handlerProp RDF:resource="urn:mimetype:handler:text/x-python"/&amp;gt;
  &amp;lt;/RDF:Description&amp;gt;

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7431574182407822867?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7431574182407822867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7431574182407822867'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2009/01/opening-python-files-and-other-source.html' title='Opening Python files (and other source files) &quot;in-browser&quot; in Firefox 3.0+'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-6628638497439603112</id><published>2008-12-01T13:00:00.002-07:00</published><updated>2008-12-01T13:07:22.099-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>py.edit.js -- a simple Python editor in Javascript</title><content type='html'>Here is a simple "editor" that I made over a weekend: &lt;a href="http://py-edit-js.appspot.com/"&gt;py.edit.js&lt;/a&gt;. It runs on top of &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt;.  It does simple things such &lt;span style="font-weight:bold;"&gt;auto indent/auto dedent&lt;/span&gt; of Python code as you type it in, &lt;span style="font-weight:bold;"&gt;evaluation&lt;/span&gt; of the code, and ability to &lt;span style="font-weight:bold;"&gt;output as text or HTML&lt;/span&gt;. There is also a &lt;span style="font-weight:bold;"&gt;"bookmarklet" mode&lt;/span&gt; -- which users can drag onto their menubar of their browser, and click on it to open up a "editor" mini-window on the current page that they are viewing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-6628638497439603112?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6628638497439603112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6628638497439603112'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2008/12/pyeditjs-simple-python-editor-in.html' title='py.edit.js -- a simple Python editor in Javascript'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-2361574977112992935</id><published>2008-07-18T22:44:00.002-07:00</published><updated>2008-07-18T23:06:50.723-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Google challenge</title><content type='html'>&lt;p&gt;From the Ruby Forum: &lt;a href="http://www.ruby-forum.com/topic/156473#new"&gt;http://www.ruby-forum.com/topic/156473#new&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;blockquote&gt;
There is an array A[N] of N integers. You have to compose an array
Output[N] such that Output[i] will be equal to the product of all
 the elements of A[] except A[i].

    Example:
        INPUT:[4, 3, 2, 1, 2]
        OUTPUT:[12, 16, 24, 48, 24]

 Note: Solve it without the division operator and in O(n).
&lt;/blockquote&gt;

Here is my Python version. Note any difference between this implementation and those discussed in the Ruby Forum?
&lt;/p&gt;
&lt;pre class="codebox"&gt;
# http://www.ruby-forum.com/topic/156473#new
_input = [4, 3, 2, 1, 2]

after = []
before = []

t = 1
for x in _input:
    before.append(t) 
    t *= x

t = 1
for x in reversed(_input):
    after.append(t)
    t *= x
after.reverse()

for x, y in zip(before, after):
    print x * y

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-2361574977112992935?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2361574977112992935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2361574977112992935'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2008/07/google-challenge.html' title='Google challenge'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-2495861637662172550</id><published>2008-05-13T00:33:00.005-07:00</published><updated>2008-05-13T01:07:21.143-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>word-find.lisp</title><content type='html'>&lt;p&gt;
I wrote this in 2004. Given a set of words, it generates word finder puzzles &amp; also generates a solution for that puzzle. See the bottom of this post for an example.  From what I remember, the most fun part of this tiny lisp program was writing the WALKING-ALONG macro, listed below. &lt;/p&gt;

&lt;p&gt;
Given a set of words, you need to place all the words inside the words rectangle, and fill the rest with junk characters. And the word should be placed in some random spot, going in a random direction. So while constructing the puzzle, I really don't care about the direction or the spot. I try to do those randomly. And this macro helps with that process.

&lt;/p&gt;

&lt;pre class="codebox"&gt;
(defmacro walking-along ((var array &amp;amp;key (direction (required-argument))
                              start-x start-y)
                         &amp;amp;body body)
  `(block nil
     (let ((.x. ,start-x) (.y. ,start-y))
       (symbol-macrolet ((,var (aref ,array .y. .x.)))
         (loop
           (unless (array-in-bounds-p ,array .y. .x.)
             (return))
           ,@body
           (ecase ,direction
             (:UP      (decf .y.))
             (:DOWN    (incf .y.))
             (:LEFT    (decf .x.))
             (:RIGHT   (incf .x.))
             (:DL-UP   (decf .x.) (decf .y.))
             (:DL-DOWN (decf .x.) (incf .y.))
             (:DR-UP   (incf .x.) (decf .y.))
             (:DR-DOWN (incf .x.) (incf .y.))))))
    (values)))
&lt;/pre&gt;



&lt;pre class="codebox"&gt;
;;; word-find.lisp -- 
;;;
;;; Author: &amp;lt;sri -at- asu -dot- edu&amp;gt;
;;; Date: 2004-02-25T16:56:51
;;;
;;; Ideas:
;;;
;;;  o All the characters in the array should be part of a word.
;;;    Find words  that are randomly made up due to the intersection
;;;    of all the words and add it to the list of words.
;;;  o Difficulties:  either have a large matrix with small words, or so
;;;    similar words (characters)  that overlap.
;;;  o Try circular ones [for the array].
;;;
;;; [Tested and implemented under
;;;  CMU Common Lisp CVS Head 2003-10-03 00:16:55]
;;;
;;; This code is
;;;     Copyright (c) 2004 by Sriram Thaiyar.
;;; The terms are: You may do as you please with this code, as long as
;;; you do not delete this notice or hold me responsible for any outcome
;;; related to its use.


(defmacro walking-along ((var array &amp;amp;key (direction (required-argument))
                              start-x start-y)
                         &amp;amp;body body)
  `(block nil
     (let ((.x. ,start-x) (.y. ,start-y))
       (symbol-macrolet ((,var (aref ,array .y. .x.)))
         (loop
           (unless (array-in-bounds-p ,array .y. .x.)
             (return))
           ,@body
           (ecase ,direction
             (:UP      (decf .y.))
             (:DOWN    (incf .y.))
             (:LEFT    (decf .x.))
             (:RIGHT   (incf .x.))
             (:DL-UP   (decf .x.) (decf .y.))
             (:DL-DOWN (decf .x.) (incf .y.))
             (:DR-UP   (incf .x.) (decf .y.))
             (:DR-DOWN (incf .x.) (incf .y.))))))
    (values)))

(defun elts-at (array x y length direction)
  (let ((elts '())
        (i -1))
    (walking-along (e array :direction direction :start-x x :start-y y)
      (when (= (incf i) length)
        (return))
      (push e elts))
    (nreverse elts)))

(defun (setf elts-at) (new array x y direction &amp;amp;optional (length (length new)))
  (let ((i -1) (positions '()))
    (walking-along (e array :direction direction :start-x x :start-y y)
      (when (= (incf i) length)
        (return))
      (let ((elt (elt new i)))
        (setq e elt)
        (push (list elt .x. .y.) positions)))
    positions))

(defparameter *directions*
  '(:UP :DOWN :LEFT :RIGHT :DL-UP :DL-DOWN :DR-UP :DR-DOWN))

(let ((dirs nil)
      (null-returned nil))
  (defun random-direction (&amp;amp;optional reset)
    (when (or reset null-returned)
      (setq dirs (copy-list *directions*)
            null-returned nil))
    (if (and (null dirs) (null null-returned))
        (progn
          (setq null-returned t)
          nil)
        (let ((dir (nth (random (length dirs)) dirs)))
          (setq dirs (delete dir dirs))
          dir)))
  )

(defparameter *colors*
  '(:RED :BLUE :GREEN :ORANGE :PURPLE :GRAY :BROWN :PINK))

(let ((cols nil))
  (defun random-color ()
    (when (null cols)
      (let ((*directions* *colors*)) ;This is code reuse ;)
        (push (random-direction t) cols)
        (loop
          (let ((next (random-direction)))
            (when (null next)
              (return))
            (push next cols)))))
    (pop cols))
  )


;;; Return values for RANDOM-FIT &amp;amp; FORCE-FIT:
;;;  (&amp;lt;seq&amp;gt; &amp;lt;col&amp;gt; (&amp;lt;c0&amp;gt; &amp;lt;x0&amp;gt; &amp;lt;y0&amp;gt;) ...)

(defun random-fit (seq array width height)
  (let ((x (random width))
        (y (random height))
        (len (length seq)))
    (loop
      (let ((dir (random-direction)))
        (when (null dir)
          (return nil))
        (let ((old (elts-at array x y len dir)))
          (when (and (every (complement #'characterp) old)
                     (= (length old) len))
            (return
              (list* seq
                     (random-color)
                     (setf (elts-at array x y dir) seq)))))))))

(defun force-fit (seq array)
  (let ((open-spaces '())
        (dim (array-dimensions array)))
    (dotimes (x (car dim))
      (dotimes (y (cadr dim))
        (dolist (dir *directions*)
          (let ((count 0))
            (walking-along (e array :direction dir :start-x x :start-y y)
              (if (characterp e)
                  (return)
                  (incf count)))
            (push (list count x y dir)
                  open-spaces)))))
    (setq open-spaces
          (sort open-spaces #'&amp;gt; :key #'first))
    (let ((len (length seq)))
      (setq open-spaces
            (delete-if (lambda (n) (&amp;lt; n len)) open-spaces :key #'first))
      (when open-spaces
        (let ((x (nth (random (length open-spaces)) open-spaces)))
          (list* seq
                 (random-color)
                 (setf (elts-at array (second x) (third x) (fourth x))
                       seq)))))))

(defvar *error-on-nonfit* nil)

(defun wordfind-simple (words width height)
  (setq words (sort (copy-seq words) #'&amp;lt; :key #'length))
  (let ((array (make-array (list height width) :initial-element nil))
        (solution '()))
    (dolist (word words)
      (dotimes (i 15 (let ((x (force-fit word array)))
                       (if x
                           (push x solution)
                           (when *error-on-nonfit*
                             (error "Unable to fit ~A in ~S" word array)))))
        (let ((x (random-fit word array width height)))
          (when x
            (push x solution)
            (return)))))
    (dotimes (i (array-total-size array))
      (unless (characterp (row-major-aref array i))
        (setf (row-major-aref array i)
              (char "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (random 26))))
      (setf (row-major-aref array i)
            (char-upcase (row-major-aref array i))))
    (values array solution)))


(defun generate-html (array solution output)
  (let ((words (mapcar #'car solution))
        (solution-pathname
         (make-pathname
          :defaults output
          :name (concatenate 'string (pathname-name output) "-sol"))))
    (flet
      ((generate-html-1 (&amp;amp;optional solution-p)
         (with-open-file (stream (if solution-p solution-pathname output)
                                 :direction :output
                                 :if-exists :supersede)
           (html (:stream stream)
            (head ()
             (title () (if solution-p "Word Finder: Solution" "Word Finder")))
            (body ()
             (strong () "Words: ")
             (if solution-p
                 (maplist (lambda (elts)
                            (format t "&amp;lt;font color=\"~A\"&amp;gt;~A&amp;lt;/font&amp;gt;~@[, ~]"
                                    (cadar elts)
                                    (string-capitalize (caar elts))
                                    (cdr elts)))
                          solution)
                 (format t "~{~A~^,&amp;amp;nbsp; ~}"
                         (mapcar #'string-capitalize words)))
             (br ())
             (p (:align :center)
              (table (:border t :width 100 :cellpadding 5)
               (when solution-p
                 (dolist (x solution)
                   (destructuring-bind (word color . positions)
                       x
                     (declare (ignore word))
                     (dolist (pos positions)
                       (let ((x (cadr pos)) (y (caddr pos)))
                         (unless (char-equal (car pos) (aref array y x))
                           (error "Characters don't match"))
                         (setf (aref array y x)
                               (cons color (car pos))))))))
                   (let ((dim (array-dimensions array)))
                     (dotimes (x (car dim))
                       (tr ()
                        (dotimes (y (cadr dim))
                          (td (:align :center)
                           (let ((elt (aref array y x)))
                             (if (consp elt) ;Solution and part of word
                                 (format t
                                         "&amp;lt;strong&amp;gt;&amp;lt;font color=\"~A\"&amp;gt;~C&amp;lt;/font&amp;gt;~
                                          &amp;lt;/strong&amp;gt;"
                                         (car (aref array y x))
                                         (char-upcase (cdr (aref array y x))))
                                 (format t "~C" (aref array y x)))))))))))
             (br ())
             (unless solution-p
               (p (:align :center)
                (a (:href (namestring solution-pathname)) "Solution"))))))))
      (generate-html-1)
      (generate-html-1 t)
      (values))))

(defun make-wordfind (&amp;amp;key (total-words 300) (width 20) (height 20)
                           (dict #p"/etc/alternatives/dictionary")
                           (output #p"word-find.html"))
  (let ((*error-on-nonfit* nil)
        (words '()))
    (if (or (stringp dict) (pathnamep dict))
        (with-open-file (stream dict)
          (let ((count 0))
            (loop
              (when (&amp;gt; count total-words)
                (return))
              (file-position stream (random (file-length stream)))
              (loop
                (let ((next (read-char stream nil nil)))
                  (cond ((null next) (return))
                        ((char= next #\Newline)
                         (let ((word (read-line stream nil nil)))
                           (when (&amp;gt; (length word) 0)
                             (push word words)
                             (incf count))
                           (return)))))))))
        (setq words dict))
    (multiple-value-bind (array solution)
        (wordfind-simple words width height)
      (generate-html array solution output))
    (values)))

&lt;/pre&gt;

&lt;br/&gt;
&lt;p&gt;


&lt;h4&gt;Here is a sample output &amp; its solution:&lt;/h4&gt;
&lt;hr/&gt;

&lt;STRONG&gt;Words: &lt;/STRONG&gt;Supercomputers,&amp;nbsp; Contribution,&amp;nbsp; Conditioners,&amp;nbsp; Incendiaries,&amp;nbsp; Imprecisely,&amp;nbsp; Talkatively,&amp;nbsp; Playgrounds,&amp;nbsp; Subchannels,&amp;nbsp; Congressman,&amp;nbsp; Chronograph,&amp;nbsp; Spiritual,&amp;nbsp; Toryizes,&amp;nbsp; Coverage,&amp;nbsp; Rainfall,&amp;nbsp; Climbing,&amp;nbsp; Hostile,&amp;nbsp; Dumping,&amp;nbsp; Adjoin,&amp;nbsp; Foils,&amp;nbsp; Sighs,&amp;nbsp; Casey&lt;BR&gt;
&lt;P ALIGN="center"&gt;
&lt;TABLE BORDER CELLPADDING=5 WIDTH=100&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;W&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;W&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;W&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;W&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;/TR&gt;
&lt;/TABLE&gt;
&lt;/P&gt;
&lt;BR&gt;

&lt;hr/&gt;
&lt;STRONG&gt;Words: &lt;/STRONG&gt;&lt;font color="PINK"&gt;Supercomputers&lt;/font&gt;, &lt;font color="BLUE"&gt;Contribution&lt;/font&gt;, &lt;font color="ORANGE"&gt;Conditioners&lt;/font&gt;, &lt;font color="GRAY"&gt;Incendiaries&lt;/font&gt;, &lt;font color="GREEN"&gt;Imprecisely&lt;/font&gt;, &lt;font color="BROWN"&gt;Talkatively&lt;/font&gt;, &lt;font color="RED"&gt;Playgrounds&lt;/font&gt;, &lt;font color="ORANGE"&gt;Subchannels&lt;/font&gt;, &lt;font color="GREEN"&gt;Congressman&lt;/font&gt;, &lt;font color="PINK"&gt;Chronograph&lt;/font&gt;, &lt;font color="GRAY"&gt;Spiritual&lt;/font&gt;, &lt;font color="PURPLE"&gt;Toryizes&lt;/font&gt;, &lt;font color="BLUE"&gt;Coverage&lt;/font&gt;, &lt;font color="PINK"&gt;Rainfall&lt;/font&gt;, &lt;font color="GRAY"&gt;Climbing&lt;/font&gt;, &lt;font color="ORANGE"&gt;Hostile&lt;/font&gt;, &lt;font color="BLUE"&gt;Dumping&lt;/font&gt;, &lt;font color="RED"&gt;Adjoin&lt;/font&gt;, &lt;font color="BROWN"&gt;Foils&lt;/font&gt;, &lt;font color="GREEN"&gt;Sighs&lt;/font&gt;, &lt;font color="PURPLE"&gt;Casey&lt;/font&gt;&lt;BR&gt;
&lt;P ALIGN="center"&gt;
&lt;TABLE BORDER CELLPADDING=5 WIDTH=100&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;K&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;V&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;Y&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;W&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;Y&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;D&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;J&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;U&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;P&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;M&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;P&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;U&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;H&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;Y&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;V&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;H&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;U&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;P&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;G&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;H&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Y&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;B&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;F&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;G&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;D&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;W&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;H&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;U&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;G&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;P&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;U&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;M&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;D&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;M&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;G&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;P&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;F&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;U&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;B&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Z&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;G&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;D&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;P&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;H&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;C&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;B&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;W&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;G&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;N&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;T&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PINK"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;M&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;B&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BROWN"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;I&lt;/TD&gt;&lt;TD ALIGN="center"&gt;W&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;X&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="ORANGE"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;F&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;TD ALIGN="center"&gt;H&lt;/TD&gt;&lt;TD ALIGN="center"&gt;D&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;T&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;Y&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;I&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;Z&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="PURPLE"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;O&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;U&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;Q&lt;/TD&gt;&lt;TD ALIGN="center"&gt;A&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;P&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;L&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;Y&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;G&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;U&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;D&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="RED"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;R&lt;/TD&gt;&lt;TD ALIGN="center"&gt;V&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;M&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GRAY"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;A&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;M&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;S&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;E&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;R&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;G&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;N&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;O&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="GREEN"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;TD ALIGN="center"&gt;J&lt;/TD&gt;&lt;TD ALIGN="center"&gt;K&lt;/TD&gt;&lt;TD ALIGN="center"&gt;E&lt;/TD&gt;&lt;TD ALIGN="center"&gt;S&lt;/TD&gt;&lt;TD ALIGN="center"&gt;P&lt;/TD&gt;&lt;TD ALIGN="center"&gt;L&lt;/TD&gt;&lt;TD ALIGN="center"&gt;&lt;strong&gt;&lt;font color="BLUE"&gt;C&lt;/font&gt;&lt;/strong&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;/TABLE&gt;
&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-2495861637662172550?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2495861637662172550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2495861637662172550'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2008/05/word-findlisp.html' title='word-find.lisp'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-2405616028665044538</id><published>2008-04-13T22:39:00.005-07:00</published><updated>2008-04-13T23:10:15.038-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>bowling.py</title><content type='html'>&lt;p&gt;One Saturday morning, I had the urge to learn the scoring rules for the game of bowling. This program resulted from that. Guido, &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=32026"&gt;here&lt;/a&gt;,  talks about his bowling program that uses a simple data structure: list of lists to represent frames. I do the same.
&lt;/p&gt;
&lt;pre class="codebox"&gt;
# Sat March 22, 2008 (9am)
# bowling.py -- calculates scores, doesn't enforce rules

# create new instance for each player.
# Public API: knocked_down(npins)
# just invoke that -- will automatically deduce
# which frame you are in.
class BowlingGame(object):
    def __init__(self):
        self.f = [[None, None] for x in range(12)]
        self.cf = 0 # current frame

    def knocked_down(self, npins):
        f = self.f[self.cf]
        if f[0] is None:
            f[0] = npins
        else:
            f[1] = npins
        if npins == 10 or f[1] is not None:
            self.cf += 1

    def get_score(self):
        total = 0
        complete = True
        for i, f in enumerate(self.f):
            if i &amp;gt; 9:
                break
            elif f[0] is None: # hasn't bowled this frame
                break
            elif f[0] == 10: # strike
                if self.f[i + 1][0] is None and \
                   (self.f[i + 1][1] is None or self.f[i + 2][0] is None):
                    complete = False
                    break
                # strike -- next 2 bowls (both of which can be in the same frame!)
                total += 10 + self.f[i + 1][0]
                if self.f[i + 1][1] is None:
                    total += self.f[i + 2][0]
                else:
                    total += self.f[i + 1][1]
            elif f[1] is None: # hasn't bowled 2nd bowl
                complete = False
                break
            elif f[0] + f[1] == 10: # spare
                if self.f[i + 1][0] is None:
                    complete = False
                    break
                total += 10 + self.f[i + 1][0]
            else:
                total += f[0] + f[1]            
        return total, complete


#
# Tests
#
def reporterror(actual, expected):
    if actual != expected:
        print 'actual: %s\nexpected: %s' % (actual, expected)
        raise Exception

def test1():
    game = BowlingGame()
    game.knocked_down(7)
    game.knocked_down(2)
    reporterror(game.get_score()[0], 9)

def test2():
    game = BowlingGame()
    for i in range(12):
        game.knocked_down(10)
    reporterror(game.get_score()[0], 300)

def test3():
    import random
    for i in range(1000):
        bowls = [random.randint(0, 4) for i in range(20)]
        game = BowlingGame()
        for b in bowls:
            game.knocked_down(b)
        reporterror(game.get_score(), (sum(bowls), True))

# wikipedia data:
# http://en.wikipedia.org/wiki/Ten-pin_bowling#Rules_of_play
def test4():
    game = BowlingGame()
    map(game.knocked_down, [10, 10, 4, 2])
    reporterror(game.get_score(), (46, True))
def test5():
    game = BowlingGame()
    map(game.knocked_down, [7, 3, 4, 2])
    reporterror(game.get_score(), (20, True))
def test6():
    game = BowlingGame()
    map(game.knocked_down, [10, 3, 6])
    reporterror(game.get_score(), (28, True))

def test7():
    game = BowlingGame()
    for i in range(10):
        game.knocked_down(10)
    game.knocked_down(7)
    game.knocked_down(1)
    reporterror(game.get_score(), (285, True))

def t():
    for i in range(100):
        try:
            name = "test%d" % (i+1)
            fn = globals()[name]
            print "testing", name
        except KeyError:
            break
        else:
            fn()

if __name__ == "__main__":
    t()

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-2405616028665044538?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2405616028665044538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2405616028665044538'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2008/04/bowlingpy.html' title='bowling.py'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-9195867435733491147</id><published>2008-02-14T23:18:00.001-07:00</published><updated>2008-02-14T23:19:57.347-07:00</updated><title type='text'>done with this blog (at least for a while)</title><content type='html'>it is time to try other things!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-9195867435733491147?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/9195867435733491147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/9195867435733491147'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2008/02/done-with-this-blog-at-least-for-while.html' title='done with this blog (at least for a while)'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-1438961380298311223</id><published>2008-02-08T01:09:00.001-07:00</published><updated>2008-02-08T01:13:40.533-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Email a directory</title><content type='html'>This is how I email a directory to myself -- I cd to the directory and type this command there. Also, I set up a Gmail filter and put unique words into this script that the filter will recognize. So the directory will be tarred, gzipped and sent to my Gmail account and will arrive in a specific label. Works with Python 2.5

&lt;pre class="codebox"&gt;
#! /usr/bin/env python2.5
# -*- Python -*-

import os
import datetime
import smtplib
import tarfile
import mimetypes
from email import Encoders
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
import tempfile
import getpass, socket


me = getpass.getuser() + '@' + socket.gethostname()
if not getpass.getuser() or not  socket.gethostname():
    print "Can't set email From"
    sys.exit(1)


def main():
    dirname = os.path.basename(os.getcwd())
    try:
        preferredname = raw_input('Default: [%s]\nPreferred Name: ' %
                                  dirname)
    except (KeyboardInterrupt, EOFError):
        pass
    else:
        dirname = preferredname.strip()

    
    to = "YOUR-EMAIL-ADDRESS"
    archive_name = os.path.join(tempfile.gettempdir(),
                                "%s.tar.gz" % dirname)
    now = datetime.datetime.today()    

    print "Creating message..."
    msg = MIMEMultipart()
    msg["Subject"] = "%s %s Backup [%d-%02d-%02d]" % (
        socket.gethostname(), dirname, now.year, now.month, now.day)
    msg["From"] = me
    msg["To"] = to
    # message has body:
    # this can be used to direct this backup email to a Gmail Filter
    # YOUR GMAIL FILTER WORD
    msg.preamble = "%s %s Backup" % (socket.gethostname(), dirname)
    msg.epilogue = ""

    if os.path.exists(archive_name):
        os.remove(archive_name)

    print "Creating gzipped-tar file..."
    tar = tarfile.open(archive_name, "w:gz")
    tar.add(".")
    tar.close()


    print "Attaching MIME to message..."
    ctype, encoding = mimetypes.guess_type("%s.tar.gz" % dirname)
    maintype, subtype = ctype.split("/", 1)
    mime = MIMEBase(maintype, subtype)
    fp = open(archive_name, "rb")
    mime.set_payload(fp.read())
    fp.close()
    Encoders.encode_base64(mime)
    mime.add_header('Content-Disposition', 'attachment',
                    filename=os.path.basename(archive_name))
    msg.attach(mime)

    print "Sending message..."
    s = smtplib.SMTP()
    s.connect()
    s.sendmail(me, [to], msg.as_string())
    s.close()

    os.remove(archive_name)


if __name__ == "__main__":
    main()

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-1438961380298311223?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1438961380298311223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1438961380298311223'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2008/02/email-directory.html' title='Email a directory'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-8481522546304994420</id><published>2007-12-19T01:47:00.000-07:00</published><updated>2007-12-19T16:53:05.967-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Quick: my Macbook Pro and Pulley</title><content type='html'>&lt;p&gt;I got my Macbook Pro on Sunday, December 16 2007. Loving it so far! Still waiting for the David Pogue's &lt;a href="http://www.amazon.com/Mac-OS-Leopard-Missing-Manual/dp/059652952X"&gt;Mac OS X Leopard: The Missing Manual&lt;/a&gt;, which should arrive tomorrow.
&lt;/p&gt;

&lt;p&gt;So, I've been kinda annoyed with Google Reader and have been wanting to create my own Reader -- I'm calling it &lt;span style="font-weight:bold;"&gt;pulley&lt;/span&gt;. More details as I start to work on it. I've been doing way too much talking and reading pointless tech news websites, and random stuff and not enough coding, hacking. All that ends today!

&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-8481522546304994420?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8481522546304994420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8481522546304994420'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/12/quick-my-macbook-pro-and-pulley.html' title='Quick: my Macbook Pro and Pulley'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7283490886861298122</id><published>2007-12-12T19:36:00.000-07:00</published><updated>2007-12-19T16:52:54.740-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>The Feyerabend Project &amp; Gerry Sussman</title><content type='html'>&lt;p&gt;From &lt;a href="http://www.dreamsongs.com/Feyerabend/Feyerabend.html"&gt;The Feyerabend Project&lt;/a&gt; -- which I think was started by Richard P. Gabriel -- a quote by Gerry Sussman:
&lt;/p&gt;
&lt;p&gt;
&lt;blockquote&gt;

     Computer Science is in deep trouble. Structured design is a failure. Systems, as currently engineered, are brittle and fragile. They cannot be easily adapted to new situations. Small changes in requirements entail large changes in the structure and configuration. Small errors in the programs that prescribe the behavior of the system can lead to large errors in the desired behavior. Indeed, current computational systems are unreasonably dependent on the correctness of the implementation, and they cannot be easily modified to account for errors in the design, errors in the specifications, or the inevitable evolution of the requirements for which the design was commissioned. (Just imagine what happens if you cut a random wire in your computer!) This problem is structural. This is not a complexity problem. It will not be solved by some form of modularity. We need new ideas. We need a new set of engineering principles that can be applied to effectively build flexible, robust, evolvable, and efficient systems. 
&lt;/blockquote&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;blockquote&gt;
    In the design of any significant system there are many implementation plans proposed for every component at every level of detail. However, in the system that is finally delivered this diversity of plans is lost and usually only one unified plan is adopted and implemented. As in an ecological system, the loss of diversity in the traditional engineering process has serious consequences for robustness. 
&lt;/blockquote&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;blockquote&gt;

    This fragility and inflexibility must not be allowed to continue. The systems of the future must be both flexible and reliable. They must be tolerant of bugs and must be adaptable to new conditions. To advance beyond the existing problems we must change, in a fundamental way, the nature of the language we use to describe computational systems. We must develop languages that prescribe the computational system as cooperating combinations of redundant processes. 
&lt;/blockquote&gt;

&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7283490886861298122?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7283490886861298122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7283490886861298122'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/12/feyerabend-project-gerry-sussman.html' title='The Feyerabend Project &amp; Gerry Sussman'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4054274793113557035</id><published>2007-12-12T03:07:00.000-07:00</published><updated>2007-12-19T16:52:19.661-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>feedparser_debug.py</title><content type='html'>&lt;p&gt;
I love &lt;a href="http://diveintomark.org/"&gt;Mark Pilgrim&lt;/a&gt;'s &lt;a href="http://feedparser.org/"&gt;feedparser&lt;/a&gt;. But sometimes I want to &lt;span style="font-weight:bold;"&gt;see&lt;/span&gt; how a feed is parsed by feedparser. Here is a hack for that. Here is an example &amp; the source: &lt;a href="http://defcraft.org/feedparser_debug/"&gt;feedparser_debug&lt;/a&gt;. I append the source below.

&lt;pre class="codebox"&gt;
import feedparser, cgi, textwrap

html = """
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;style&amp;gt;
body {
 margin: 30px;
}
table {
 border: solid 1px;
}
.bozo {
 background: pink;
 padding: 2px;
 margin-bottom: 15px;
}
.type {
 color: gray;
 font-size: 11px;
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
%s
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
"""

table = """
&amp;lt;table cellspacing=2 cellpadding=2&amp;gt;
%s
&amp;lt;/table&amp;gt;
"""

def bozo(m):
    return '&amp;lt;div class="bozo"&amp;gt;%s&amp;lt;/div&amp;gt;' % m

def tr(k, v, typ, descend_path):
    if descend_path:
        tooltip = descend_path[0]
        for x in descend_path[1:] + [k]:
            if x.startswith('['):
                tooltip += x
            else:
                tooltip += '.' + x
        tooltip = 'title="%s | %s"' % (
            tooltip,
            typ.__name__)
    else:
        tooltip = ''
    return ('&amp;lt;tr&amp;gt;&amp;lt;td %s valign=top&amp;gt;%s&amp;lt;br/&amp;gt;&amp;lt;span class="type"&amp;gt;%s&amp;lt;/span&amp;gt;' +
            '&amp;lt;/td&amp;gt;&amp;lt;td valign=top&amp;gt;%s&amp;lt;/td&amp;gt;') % (
        tooltip,
        k,
        typ.__name__,
        v)

def enumerate_seq(seq, sorted_keys=None):
    if isinstance(seq, list):
        for idx, val in enumerate(seq):
            yield '[%s]' % idx, val
    elif isinstance(seq, (feedparser.FeedParserDict, dict)):
        for attr in (sorted_keys or sorted(seq.keys())):
            try:
                val = getattr(seq, attr)
            except AttributeError:
                val = seq[attr]
            yield attr, val


def htmlize(obj, sorted_keys=None, descend_path=[]):
    if isinstance(obj, (feedparser.FeedParserDict, dict, list)):
        res = []
        for attr, val in enumerate_seq(obj, sorted_keys):
            res.append(tr(attr,
                          htmlize(val, descend_path=descend_path+[attr]),
                          type(val),
                          descend_path))
        return table % '\n'.join(res)
    else:
        #if isinstance(obj, unicode):
        #    obj = obj.encode('ascii', 'xmlcharrefreplace')
        escaped = cgi.escape(repr(obj))
        wrapped = textwrap.wrap(escaped)
        link = ''
        if isinstance(obj, (unicode, str)):
            if obj.startswith('http://') or obj.startswith('https://'):
                if len(wrapped) &amp;lt; 200:
                    link = ' &amp;lt;a href="%s"&amp;gt;[link]&amp;lt;/a&amp;gt;' % obj
        return '\n&amp;lt;br/&amp;gt;'.join(wrapped) + link

def main(url):
    f = feedparser.parse(url)
    keys = sorted(f.keys())
    keys.remove('entries')
    keys.append('entries') # place it last
    sub = htmlize(f, keys, ['f'])
    if f.bozo:
        sub = bozo(str(f.bozo_exception)) + sub
    h = html % sub
    return h

if __name__ == '__main__':
    h = main('http://defcraft.blogspot.com/feeds/posts/default')
    open('test.html', 'w').write(h)

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4054274793113557035?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4054274793113557035'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4054274793113557035'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/12/feedparserdebugpy.html' title='feedparser_debug.py'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-1314451978739844097</id><published>2007-11-28T15:17:00.000-07:00</published><updated>2007-11-28T15:45:00.816-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Just for fun: jumbled to un-jumbled</title><content type='html'>Just for fun:

&lt;pre class="codebox"&gt;
&amp;gt;&amp;gt;&amp;gt; jumble('Now is the Time for all Good Men to come to the aid of their Country...',0)
Now is the Time for all Good Men to come to the aid of their Country... 
-----------------------------------------------------------------------
Noo rf rot Thai wmr dda Guot Mct tf iehe hi tyo ino eo eloes Ceotnml...
Noo rf rot Thai wmr dda Guot Mct tf iehe ho tyo ino eo eloes Ceitnml...
Noo rf rot Thai wmr dda Guot Mct hf iehe to tyo ino eo eloes Ceitnml...
Noo rf rot Tiah wmr dda Guot Mct hf iehe to tyo ino eo eloes Ceitnml...
Noo rf rot Tiah wmr dda Guot Mct hf iehe to tyo ino eo eloes Ceitnml...
Noo rf rot Tiih wmr dda Guot Mct hf iehe to tyo ano eo eloes Ceitnml...
Noo rs rot Tiih wmr dda Guot Mct hf iehe to tyo ano eo eloef Ceitnml...
Noo rs rot Timh wmr dda Guot Mct hf iehe to tyo ano eo eloef Ceitnil...
Noo rs rot Timh wmr dda Guot Mct hf iehe to tyo ano eo eloef Ceitnil...
Noo rs rot Timh wmr add Guot Mct hf iehe to tyo ano eo eloef Ceitnil...
Noo is rot Timh wmr add Guot Mct hf iehe to tyo ano eo eloef Ceitnrl...
Noo is rot Timh wmr ado Guot Mct hf iehe to tyo and eo eloef Ceitnrl...
Noo is rot Timh wmr ado Guot Mct hf iehe to tyo and eo eloef Ceintrl...
Noo is rot Timh wmr ado Guot Mct hf nehe to tyo aid eo eloef Ceintrl...
Noo is rot Timh wmr ado Guot Mct hf nohe to tyo aid ee eloef Ceintrl...
Noo is rft Timh wmr ado Guot Mct ho nohe to tyo aid ee eloef Ceintrl...
Nou is rft Timh wmr ado Goot Mct ho nohe to tyo aid ee eloef Ceintrl...
Nou is rfe Timh wmr ado Goot Mct ho nohe to tyo aid ee tloef Ceintrl...
Nou is rfe Timh wmf ado Goot Mct ho nohe to tyo aid ee tloer Ceintrl...
Nou is rfe Timh wmf adl Goot Mct ho nohe to tyo aid ee tooer Ceintrl...
Nou is ree Timh wmf adl Goot Mct ho nohe to tyo aid ef tooer Ceintrl...
Nou is ree Timh wmf adl Goot Mct ho nohe to tyo aid of toeer Ceintrl...
Nou is ree Timh wmf adl Goot Mct ho nohe to tyo aid of toeer Ceintrl...
Nou is ree Timh wmf adl Goot Mct ho nohe to tyo aid of toeer Ceintrl...
Nou is ree Timh wmf adl Goot Mcn ho tohe to tyo aid of toeer Ceintrl...
Nou is ree Timh wmf adl Goot Mcn ho tohe to tyo aid of toeer Ceintrl...
Nou is ree Timh fmw adl Goot Mcn ho tohe to tyo aid of toeer Ceintrl...
Now is ree Timh fmu adl Goot Mcn ho tohe to tyo aid of toeer Ceintrl...
Now is ree Timh fmu adl Goot Mcn oo tohe to tyo aid of theer Ceintrl...
Now is ree Timh fmi adl Goot Mcn oo tohe to tyo aid of theer Ceuntrl...
Now is ree Timh fmi adl Goot Mcn oo tohe to tlo aid of theer Ceuntry...
Now is ree Timh fmi adl Goot Mcn oo tohe to tle aid of theer Country...
Now is ree Timh fhi adl Goot Mcn oo tome to tle aid of theer Country...
Now is ree Timh fli adl Goot Mcn oo tome to the aid of theer Country...
Now is rce Timh fli adl Goot Men oo tome to the aid of theer Country...
Now is rce Timh fli adl Goot Men oo tome to the aid of theer Country...
Now is rce Timh fli adl Goot Men oo tome to the aid of theer Country...
Now is rhe Timc fli adl Goot Men oo tome to the aid of theer Country...
Now is rhe Time fli adl Goot Men oo tome to the aid of thecr Country...
Now is rhe Time flc adl Goot Men oo tome to the aid of their Country...
Now is rhe Time flt adl Goot Men oo come to the aid of their Country...
Now is rhe Time flt atl Good Men oo come to the aid of their Country...
Now is the Time flr atl Good Men oo come to the aid of their Country...
Now is the Time flr aol Good Men to come to the aid of their Country...
Now is the Time for all Good Men to come to the aid of their Country...
Now is the Time for all Good Men to come to the aid of their Country...
Now is the Time for all Good Men to come to the aid of their Country...
Now is the Time for all Good Men to come to the aid of their Country...
&lt;/pre&gt;

Here is the code:
&lt;pre class="codebox"&gt;
import random, string

class JumbledString(object):
    def __init__(self, original):
        self.original = list(original)
        self.remaining = list(original)
        # positions in self.jumbled that are
        # still available
        self.available = range(len(original))
        self.jumbled = self.jumble(original)

    # jumbling up all doesn't look too good.
    # let's try jumbling up only ascii lowercase.
    def jumble(self, st):
        tmp = []
        ins = []
        for (i, c) in enumerate(st):
            if c not in string.ascii_lowercase:
                self.available.remove(i)
                self.remaining.remove(c)
                ins.append((i, c))
            else:
                tmp.append(c)
        random.shuffle(tmp)
        for (i, c) in sorted(ins):
            tmp.insert(i, c)
        return tmp

    def is_done(self):
        return len(self.remaining) == 0

    def findall(self, char, string):
        res = [i for (i, c) in enumerate(string) if c == char]
        random.shuffle(res)
        return res

    def find_in_jumbled(self, char):
        res = [i
               for (i, c) in enumerate(self.jumbled)
               if c == char and i in self.available]
        assert res, "can't find char in find_in_jumbled!"
        random.shuffle(res)
        return res[0]

    def rand_swap(self):
        choice = random.choice(self.remaining)
        self.remaining.remove(choice)
        for pos in self.findall(choice, self.original):
            if pos in self.available:
                self.available.remove(pos)
                if self.jumbled[pos] == choice:
                    return pos, pos
                swappos = self.find_in_jumbled(choice)
                tmp = self.jumbled[pos]
                self.jumbled[pos] = choice
                self.jumbled[swappos] = tmp
                return pos, swappos
        assert False, "this can't happen in rand_swap!"

    def get_jumbled(self):
        return ''.join(self.jumbled)


def jumble(sentence, print_marker=True):
    print sentence, '\n', '-'*len(sentence)
    i = 1
    j = JumbledString(sentence)
    while not j.is_done():
        a, b = j.rand_swap()
        print j.get_jumbled()
        if print_marker:
            print marker(len(sentence), min(a, b), max(a, b))
        i += 1
        assert i &lt; 2*len(sentence) # just for safety

def marker(slen, a, b):
    if a == b:
        return ' '*a + '^' + ' '*(slen-a-1)
    else:
        return ' '*a + '^' + '-'*(b-a-1) + '^' + ' '*(slen-b-1)

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-1314451978739844097?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1314451978739844097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1314451978739844097'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/11/just-for-fun-jumbled-to-un-jumbled.html' title='Just for fun: jumbled to un-jumbled'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7290280893526374705</id><published>2007-10-23T04:13:00.001-07:00</published><updated>2007-10-23T04:20:47.497-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>What programming language should I start with?</title><content type='html'>Over on news.ycombinator.com, someone asked the question:
&lt;blockquote&gt;What programming language should I start with?
&lt;/blockquote&gt;

This was my response:

&lt;blockquote&gt;
&lt;p&gt;Here are the languages that have big communities: Perl, Python, Ruby, PHP, Javascript, C#/VB.NET and Java.&lt;/p&gt;

&lt;p&gt;Subscribe to lots of blogs from each community. (Many of them have planet aggregators like "Planet Python" and "Planet Ruby".) Also visit local user groups, wherever your are.&lt;/p&gt;

&lt;p&gt;Read/visit them for a while -- say a month or two. Whichever community makes you go, "wow, that's cool" -- join that community and learn the language. You can also interact with those communities via Google Groups.&lt;/p&gt;

&lt;p&gt;Lots of people will say -- "that's easy" or "this is elegant" or "that language sucks". Feel free to ignore them.&lt;/p&gt;
&lt;/blockquote&gt;

And the response to my response, which I really liked :-)
&lt;blockquote&gt;
Excellent advice. Non-religious, informative, and true.
&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7290280893526374705?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7290280893526374705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7290280893526374705'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/10/what-programming-language-should-i.html' title='What programming language should I start with?'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7933401921863351391</id><published>2007-07-24T06:11:00.000-07:00</published><updated>2007-07-24T06:19:34.210-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>my dot emacs: Shift to Control</title><content type='html'>&lt;p&gt;
I can still remember my left pinky hurting badly, from
pressing the Control key to invoke commands in Emacs.
But then I swapped Shift &amp; Control. And I've been 
happy ever since. Shift is in a perfect location
(not too far below like Control)
and is on both sides of the keyboard -- this even
on the worst keyboards that I had to endure while
in college.
&lt;/p&gt;

&lt;p&gt;Now, some things break when you do this.
Control-Space sets the mark (and still
does), but Shift-Space doesn't -- it
simply inserts a space. Control-G can break
out of infinite loops in Emacs Lisp -- Shift-g
can't do that (unless you modify the quit_char
in src/keyboard.c before building Emacs). Also,
typing upcase or capitilized characters are a
bit harder -- especially because I move my
entire hand off the keyboard to hit the Control
key -- no more use of the pinky in unnatural
positions! And when you cut-n-paste, upper
case characters run commands!! (Although,
I haven't needed it, this shouldn't be too hard
to overcome -- you can setup things so that
a keypress swaps Control &amp; Shift, and then
pastes the contents of the clipboard, 
and the re-swaps them again.)

&lt;/p&gt;


&lt;p&gt;
Despite the problems, this has been worth
it for me. And here is the code for all this.
I think this is all the code -- I haven't really looked at
it since I wrote it about 6 years ago. This
works on both Windows and Linux (I think, this will
really work everywhere...):
&lt;/p&gt;

&lt;pre class="codebox"&gt;
;;; control becomes shift and vice-versa. when this happens certain
;;; things are broken: c-space sets mark, however shift-space doesn't
;;; anymore.  for esc, use alt (press this with the thumb, which
;;; doesn't do *anything* except hit the damn space bar) plus the key.
;;; expriment: 04:29PM Friday November 23 2001.  hopefully, things
;;; will be much easier this way.
;;; to do: change esc-c-f to esc-F.  also need to be careful about
;;; esc-ctrl-&lt;non-letter&gt; like esc-ctrl-. and esc-ctrl-backspace. how to
;;; fix these.  also since i usually type a lowercase word and want to
;;; upcase or capatilize it afterwards, make those commands default to the
;;; previous word.

;;; Another idea:  make keyboard-translate-table buffer local so that
;;; in certain modes, like gnus, we can operate normally (or maybe
;;; change it during an entry and exit hook.

(defun keyboard-translate-swap (a b)
  (keyboard-translate a b)
  (keyboard-translate b a))

(defvar previous-keyboard-translate-table nil)

(defun normalize-keyboard ()
  (interactive)
  (setq previous-keyboard-translate-table keyboard-translate-table
        keyboard-translate-table nil))

(defun revert-keyboard ()
  (interactive)
  (setq keyboard-translate-table previous-keyboard-translate-table))

;;; Emacs Manual, "Translating Input Events"
(setq keyboard-translate-table
      (make-char-table 'keyboard-translate-table nil))

;;; Swap Control-&lt;letter&gt; and uppercase letters.
(let ((ctrl 1) (upcase-beg (1- ?A)) (letters 26))
  (while (&lt;= ctrl letters)
    (keyboard-translate-swap ctrl (+ upcase-beg ctrl))
    (setq ctrl (1+ ctrl))))

&lt;/pre&gt;

&lt;p&gt;And this piece of code quickly upcases or capitalizes the previous word that
you just typed. I have it bound to F6:
&lt;/p&gt;

&lt;pre class="codebox"&gt;
(defvar my-correct-case-last-arg nil)

(defun my-correct-case (arg)
  (interactive "p")
  (let ((fn (cond ((eq last-command 'my-correct-case)
                   (setq arg my-correct-case-last-arg)
                   'capitalize-word)
                  (t (setq my-correct-case-last-arg arg)
                     'upcase-word))))
    (save-excursion
      (funcall fn (- arg)))))

&lt;/pre&gt;

&lt;p&gt;
These days I run Emacs via Putty from a Windows machine.
This is how I cut-n-paste in Putty -- when you right click
on the terminal, Putty sends the contents of the clipboard
to the terminal.  There are 2 parts to this: the Emacs part
and the shell part. First, I have to suspend Emacs and
go to the shell, where is type the alias c:
&lt;/p&gt;

&lt;pre class="codebox"&gt;
alias c='echo Hit Ctrl-C to end; cat &amp;gt; ~/x'
&lt;/pre&gt;

&lt;p&gt;Next, back in Emacs, I hit F10 -- this function is bound 
to that key:
&lt;/p&gt;

&lt;pre class="codebox"&gt;
(defun my-paste ()
  (interactive)
  (if (not (file-exists-p "~/x"))
      (message "~/x doesn't exist")
    (insert-file-contents "~/x")
    (message "Pasted contents of ~/x")))

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7933401921863351391?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7933401921863351391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7933401921863351391'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/07/my-dot-emacs-shift-to-control.html' title='my dot emacs: Shift to Control'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-8626593344727570821</id><published>2007-07-05T04:41:00.000-07:00</published><updated>2007-07-05T04:58:59.753-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><title type='text'>Firefox Greasemonkey hack</title><content type='html'>Firefox &lt;a href="http://www.greasespot.net/"&gt;Greasemonkey&lt;/a&gt; hack: &lt;a href="http://defcraft.org/%7Esri/myGM-hacks/sri-goog-amazon.user.js"&gt;sri-goog-amazon.user.js&lt;/a&gt;. (make sure you know what you're doing if you install this...)

Select a piece of text with your mouse and hit one of these keys:

&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;ALT-A&lt;/span&gt;: searches Amazon.com for the selected text, in a background tab
&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;ALT-G&lt;/span&gt;: does the above with Google.com
&lt;/li&gt;&lt;/ul&gt;Also, without any selection, ALT-A and ALT-G will take you to Amazon.com &amp;amp; Google.com respectively.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-8626593344727570821?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8626593344727570821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8626593344727570821'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/07/firefox-greasemonkey-hack.html' title='Firefox Greasemonkey hack'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-6725022453405918105</id><published>2007-06-22T16:33:00.000-07:00</published><updated>2007-06-22T17:04:52.114-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>strftime helper</title><content type='html'>&lt;p&gt;I can never remember the syntax for &lt;a href="http://docs.python.org/lib/module-time.html"&gt;strftime&lt;/a&gt; -- so I wrote a little helper for it: &lt;a href="http://defcraft.org/~sri/hacks/pycmds/strftime_helper.py"&gt;strftime_helper.py&lt;/a&gt;, which uses &lt;a href="http://defcraft.org/~sri/hacks/pycmds/pii.py"&gt;pii.py&lt;/a&gt; (see previous post, &lt;a href="http://defcraft.blogspot.com/2007/06/extending-pythons-interactive.html"&gt;Extending Python's Interactive Interpreter&lt;/a&gt;). Here is an interactive session with it:
&lt;/p&gt;

&lt;pre class="codebox"&gt;
&amp;gt;&amp;gt;&amp;gt; pd
===============================================================================
= pd help =

localet, localed, localedt  - Locale Time, Locale Date, Locale Date &amp; Time
hh24, hh, mm, ss, am, pm    - 24-Hour, Hour, Minute, Second, Am, Pm
dow, dom, doy               - Day Of {Week, Month, &amp; Year} respectively
swoy, mwoy                  - Week Of Year considering either Sunday or Monday
                                as first day of week
yy, yyyy                    - Year without century &amp; Year with century
tz                          - Timezone
mon..sun, monday..sunday    - Weekday in Abbrev or Long form
jan..dec, january..december - Month in Abbrev or Long form

? localet hh24:mm:ss, pm
2007-06-22 19:36:53 formats to
19:36:53 19:36:53, PM
'%X %H:%M:%S, %p'
? jun dom, yyyy (it's a sunday)
2007-06-22 19:38:51 formats to
Jun 22, 2007 (it's a Friday)
"%b %d, %Y (it's a %A)"
? [ENTER] or Control-D
&amp;gt;&amp;gt;&amp;gt; _
"%b %d, %Y (it's a %A)"

&lt;/pre&gt;


&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Things to note:&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;although the new format directives are easier to remember (&lt;span style="font-weight:bold;"&gt;dom&lt;/span&gt; of day of the month, any of &lt;span style="font-weight:bold;"&gt;mon&lt;/span&gt;, &lt;span style="font-weight:bold;"&gt;tue&lt;/span&gt;, &lt;span style="font-weight:bold;"&gt;wed&lt;/span&gt;, ..., &lt;span style="font-weight:bold;"&gt;sun&lt;/span&gt; for a short weekday name, any of &lt;span style="font-weight:bold;"&gt;january&lt;/span&gt;, &lt;span style="font-weight:bold;"&gt;feburary&lt;/span&gt;, ..., &lt;span style="font-weight:bold;"&gt; december &lt;/span&gt;for a long month name, &lt;span style="font-weight:bold;"&gt;tz&lt;/span&gt; for timezone), a help screen is printed out each time you type &lt;span style="font-weight:bold;"&gt;pd&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;you end the interactive session with &lt;span style="font-weight:bold;"&gt;pd&lt;/span&gt; by  hitting Ctrl-D or by passing it a empty line. The &lt;span style="font-weight:bold;"&gt;_&lt;/span&gt; variable will be set to the result of pd: the actual format control that strftime interprets
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given Python's friendliness to newbies, there should be a newbie.py supplied with the standard distribution that "simplifies" many such tasks for newbies...
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-6725022453405918105?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6725022453405918105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6725022453405918105'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/06/strftime-helper.html' title='strftime helper'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-5051622881026703174</id><published>2007-06-17T01:04:00.001-07:00</published><updated>2007-06-17T03:15:18.310-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Extending Python's Interactive Interpreter</title><content type='html'>&lt;p&gt;[The code for all this is here: &lt;a href="http://defcraft.org/~sri/hacks/pii.py"&gt;pii.py&lt;/a&gt;]
&lt;/p&gt;

&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Update:&lt;/span&gt; I've only tried this under Linux; the special commands doesn't seem to work under IDLE. Also,  you need to execfile pii.py, and not import it...&lt;/p&gt;

&lt;p&gt;I've written some code to help the interactive interpreter accept simple commands. Commands like "ls" and those like "cd ~/tmp". Commands without arguments -- simple commands -- can be Python objects. But for those with arguments (special commands), we need a little magic: when there is a space between a command and its argument ("cd ~/tmp"), Python raises a SyntaxError. And the SyntaxError contains the problematic line:
&lt;/p&gt;
&lt;pre class="codebox"&gt;
&amp;gt;&amp;gt;&amp;gt; try:
...   eval('a b')
... except SyntaxError, s:
...   print repr(s.text)
...
'a b'
&lt;/pre&gt;

&lt;p&gt;
So we simply "catch" the error and extract the command that needs to be executed and execute it.  The two hook functions, &lt;a href="http://docs.python.org/lib/module-sys.html"&gt;sys.displayhook&lt;/a&gt; and &lt;a href="http://docs.python.org/lib/module-sys.html"&gt;sys.excepthook&lt;/a&gt; are necessary to make this happen.  sys.displayhook is needed to display the simple commands &amp; sys.excepthook is needed to extract out the special commands and run them. We replace  both the hooks like so:
&lt;/p&gt;

&lt;pre class="codebox"&gt;
def mydisplayhook(value):
    if value is not None:
        # this'll only invoke simplecmds (or
        # cmds that install themselves in
        # __builtins__) -- the specialcmds are
        # executed in myexcepthook
        if isinstance(value, SimpleCmd):
            out = value()
            if out:
                print out
        else:
            __builtins__._ = value
            print repr(value)
sys.displayhook = mydisplayhook

def myexcepthook(type, value, tb):
    # imports giving rise to syntaxerror shouldn't
    # be considered a s cmds
    if type is SyntaxError and value.filename=='&amp;lt;stdin&amp;gt;':
        # might be a cmd of ours
        line = value.text
        # if user is entering a multiline expr
        # (line[0]!=' ') -- they indent everything
        # other than first line -- don't consider
        # that a cmd
        if line and line[0] not in ' \t':
            cmd = value.text.split()[0]
            if cmd in specialcmds:
                fn = specialcmds[cmd]
                arg = line[len(cmd):]
                fn(arg)
                return
    traceback.print_exception(type, value, tb)
sys.excepthook = myexcepthook
&lt;/pre&gt;

&lt;p&gt;
Two points:
&lt;ul&gt;&lt;li&gt;Special commands receive a single string -- it is up to the command to split it into multiple arguments, if necessary&lt;/li&gt;
&lt;li&gt;also, simple commands sit in the __builtins__ namespace, so even if you replace it, you can get it back by saying "del command-name")&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;
Here is the whole thing. It sits in my &lt;a href="http://docs.python.org/tut/node4.html#SECTION004240000000000000000"&gt;pythonrc &lt;/a&gt;  file. You can download it &lt;a href="http://defcraft.org/~sri/hacks/pii.py"&gt;here&lt;/a&gt;.
&lt;/p&gt;

&lt;pre class="codebox"&gt;
import sys, os, datetime, traceback, commands


specialcmds = {}
allcmds = []

class CmdMeta(type):
    def __init__(cls, name, bases, dict):
        super(CmdMeta, cls).__init__(cls, name, bases, dict)
        if name == 'Cmd': return
        simplecmds = {}
        specials = {}
        inst = cls()
        inst.install(specials, simplecmds)
        for k in simplecmds:
            setattr(__builtins__, k, SimpleCmd(simplecmds[k]))
        allcmds.append((name, cls, inst, simplecmds, specials))
        specialcmds.update(specials)

class Cmd(object):
    __metaclass__ = CmdMeta

class SimpleCmd(object):
    def __init__(self, func):
        self.func = func
    def __call__(self):
        result = self.func()
        if result:
            return str(result)

def myexcepthook(type, value, tb):
    # imports giving rise to syntaxerror shouldn't
    # be considered as cmds
    if type is SyntaxError and value.filename=='&amp;lt;stdin&amp;gt;':
        # might be a cmd of ours
        line = value.text
        # if user is entering a multiline expr
        # (line[0]!=' ') -- they indent everything
        # other than first line -- don't consider
        # that a cmd
        if line and line[0] not in ' \t':
            cmd = value.text.split()[0]
            if cmd in specialcmds:
                fn = specialcmds[cmd]
                arg = line[len(cmd):]
                fn(arg)
                return
    traceback.print_exception(type, value, tb)
sys.excepthook = myexcepthook


# reloading this file shouldn't mess up prev value
try:
    __builtins__._
except AttributeError:
    __builtins__._ = None


def mydisplayhook(value):
    if value is not None:
        # this'll only invoke simplecmds (or
        # cmds that install themselves in
        # __builtins__) -- the specialcmds are
        # executed in myexcepthook
        if isinstance(value, SimpleCmd):
            out = value()
            if out:
                print out
        else:
            __builtins__._ = value
            print repr(value)
sys.displayhook = mydisplayhook
&lt;/pre&gt;


&lt;p&gt;And here are some commands:&lt;/p&gt;

&lt;pre class="codebox"&gt;
#
# Commands:
#
class MyCmds(Cmd):
    def install(self, specialcmds, simplecmds):
        simplecmds['cmds'] = self.allcmds
    def doc(self, x):
        return getattr(x, '__doc__') or '(no doc)'
    def allcmds(self):
        "prints out all the cmds"
        print "all commands\n", 65*'='
        cmds = []
        for (name, cls, inst, simplecmds, specialcmds) in allcmds:
            simple = set(simplecmds.keys())
            specials = set(specialcmds.keys())
            both = simple &amp; specials
            simple -=  both
            specials -= both
            for k in both:
                cmds.append((k, 'both', self.doc(simplecmds[k])))
            for k in specials:
                cmds.append((k, 'special', self.doc(specialcmds[k])))
            for k in sorted(simple):
                cmds.append((k, 'simple', self.doc(simplecmds[k])))
        cmds.sort()
        for x in cmds:
            print '%-6s  %-7s    %s' % x
        

class MyReload(Cmd):
    def install(self, specialcmds, simplecmds):
        simplecmds['rl'] = self.doit
    def doit(self):
        "reloads your pythonrc startup file"
        path = os.environ.get('PYTHONSTARTUP')
        if not path:
            print "can't find your pythonstartup"
        else:
            execfile(path, globals())


class MyPwd(Cmd):
    def install(self, specialcmds, simplecmds):
        simplecmds['pwd'] = simplecmds['cwd'] = self.getcwd
    def getcwd(self):
        "prints the current working directory"
        return os.getcwd()

class MyCD(Cmd):
    def __init__(self):
        self.popdirs = []
    def install(self, specialcmds, simplecmds):
        simplecmds['popd'] = self.popd
        simplecmds['cd'] = specialcmds['cd'] = self.cd
    def popd(self):
        "changes back to directory from which we came"
        if self.popdirs:
            self.cd(self.popdirs.pop(), False)
        else:
            print 'nothing to pop back to'
    def cd(self, dir=None, insert=True):
        "changes to a given directory or user home; resolves ~ to user home"
        if not dir:
            import user
            dir = user.home
        dir = os.path.expanduser(dir.strip())
        if not os.path.isdir(dir):
            print 'not a dir:', dir
        else:
            if insert:
                self.popdirs.append(os.getcwd())
            os.chdir(dir)
            print 'changed to', dir

class MyHelp(Cmd):
    def install(self, specialcmds, simplecmds):
        specialcmds['h'] = self.help
    def help(self, x):
        "prints help to a given thing"
        help(x.strip())

class MyLs(Cmd):
    def install(self, specialcmds, simplecmds):
        specialcmds['ls'] = self.ls
        simplecmds['ls'] = self.ls
    def ls(self, dir=''):
        """run the unix command 'ls -l'"""
        dir = os.path.expanduser(dir.strip() or '.')
        print commands.getoutput('ls -l %s' % dir)

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-5051622881026703174?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/5051622881026703174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/5051622881026703174'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/06/extending-pythons-interactive.html' title='Extending Python&apos;s Interactive Interpreter'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4287494399668530563</id><published>2007-06-06T23:11:00.000-07:00</published><updated>2007-06-06T23:27:55.852-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>flatten in Python</title><content type='html'>Here it is:

&lt;pre class="codebox"&gt;
# non-recursive flatten
# requires Python 2.5 or above
def flatten(lists):
    from collections import deque
    items = deque(lists)
    while items:
        top = items.popleft()
        if isinstance(top, list):
            items.extendleft(reversed(top))
        else:
            yield top

&lt;/pre&gt;

This is the test script &lt;a href="http://defcraft.org/~sri/hacks/flatten.py"&gt;flatten.py&lt;/a&gt; with some data on performance:
&lt;pre class="codebox"&gt;
# non-recursive flatten
# requires Python 2.5 or above
def flatten(lists):
    from collections import deque
    items = deque(lists)
    while items:
        top = items.popleft()
        if isinstance(top, list):
            items.extendleft(reversed(top))
        else:
            yield top

def flatten_r(list_of_lists):
    if list_of_lists == []:
        return []
    elif isinstance(list_of_lists, list):
        result = []
        for x in list_of_lists:
            for y in flatten_r(x):
                result.append(y)
        return result
    else:
        return [list_of_lists]


# from skencil
from types import ListType
def flatten2(list):
    result = []
    for item in list:
        if type(item) == ListType:
            result = result + flatten2(item)
        else:
            result.append(item)
    return result

def count_flatten_len(x):
    if isinstance(x, list):
        return len(x)
    else:
        count = 0
        try:
            while True:
                x.next()
                count += 1
        except StopIteration:
            return count


#
# Test data:
#
t1 = [1, [2, 3, [4, 5, [[[6], 7], [[8, 9]]]]]]
t2 = [t1, [[t1], [[[t1]], t1, [[[[[t1, 'n']]], t1, t1, t1]], 'a']]]
t3 = [t2, [[t2, [t2, [[t2, [[t2, t2, t2,
                             [[[t2, [[t2, t2, t2, [[[[t2]]]]]]]]]]]]]]]]]
t4 = [[[t3, t3, [[t3, [[[t3, [[t3, [[[t3, [[[t3, t3]]]]]]]]]]]]]]]]
t5 = ['first', [[[t4, [[[t4, [[[[t4, [[[t4, 'mid']]], t4]]], t4]], t4, ]],
      t4, [[t4]]]]], 'last']


def rectest():
    global t5
    t5 = []
    for i in range(100000):
        t5 = [t5, i]

if __name__ == "__main__":
    def indent(s):
        lines = s.split("\n")
        spaces = 4 * ' '
        return "\n".join(spaces+line for line in lines)
    
    import commands

    sep = '=='*20

    # Sanity check:
    a1 = list(flatten(t5))
    a2 = flatten_r(t5)
    a3 = flatten2(t5)
    assert a1[0]=='first' and a1[-1]=='last' and a1==a2 and a2==a3
    
    cmd = ("python -mtimeit -v -n 1 -r 2 -s 'import flatten as F' '%sF.%s(F.t5)'")
    for funcname in ('flatten_r', 'flatten2', 'flatten'):
        print funcname
        out = commands.getoutput(cmd % ('', funcname))
        print indent(out)
        print sep

    print sep
    print 'recursion test'
    for funcname in ('flatten_r', 'flatten2', 'flatten'):
        print funcname
        status, out = commands.getstatusoutput(cmd % ('F.rectest(); ', funcname))
        if status:
            # recursion error (?)
            out = out.split("\n")[-1]
        print indent(out)
        print sep


"""
python -mtimeit -v -n 1 -r 2 -s 'import flatten as F'
'print F.count_flatten_len(F.flatten(F.t5))'


Output from a single run:
========================================

$ python2.5 flatten.py
flatten_r
    raw times: 3.61 3.1
    1 loops, best of 2: 3.1 sec per loop
========================================
flatten2
    raw times: 0.58 0.545
    1 loops, best of 2: 545 msec per loop
========================================
flatten
    raw times: 1.81e-05 4.05e-06
    1 loops, best of 2: 4.05 usec per loop
========================================
========================================
recursion test
flatten_r
    RuntimeError: maximum recursion depth exceeded in cmp
========================================
flatten2
    RuntimeError: maximum recursion depth exceeded in cmp
========================================
flatten
    raw times: 0.283 0.3
    1 loops, best of 2: 283 msec per loop
========================================
"""

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4287494399668530563?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4287494399668530563'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4287494399668530563'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/06/flatten-in-python.html' title='flatten in Python'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-1192180673646230948</id><published>2007-05-20T05:30:00.000-07:00</published><updated>2007-06-28T00:57:20.789-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>visualize.rb</title><content type='html'>&lt;p&gt;Here is a small script (&lt;a href="http://defcraft.org/~sri/hacks/visualize"&gt;visualize.rb&lt;/a&gt;) that helps me 
visualize the Structure of Ruby code. Before I jump into the source, I want to see the "big" picture of things. This script helps me with that.
[There is a small bug with the script -- see the source for more details.]
&lt;/p&gt;
Here it is being run on itself:

&lt;pre class="codebox"&gt;
module Visualize
  class Construct
    def initialize
    def self.fromtree
    def to_a
    def same
    def merge
    def pp
  class SourceFile
    def initialize
    def collect_requires
    def collect_tokens
    class StatementModifier
      def initialize
    def mark_statement_modifiers
    def getname
    def gather
    def pp
    def merge
  class SourcePackage
    def initialize
    def pp
def opt?
def print_tokens
def main
&lt;/pre&gt;

And here is the code structure of &lt;a href="http://www.capify.org/"&gt;Capistrano&lt;/a&gt;:
&lt;pre class="codebox"&gt;
module Capistrano
  class ServerDefinition
    def initialize
    def &lt;=&gt;
    def eql?
    def hash
    def to_s
  class Command
    def self.process
    def initialize
    def process!
    def stop!
    def logger
    def open_channels
    def replace_placeholders
    def extract_environment
...
...
   class RemoteDependency
      def initialize
      def directory
      def writable
      def command
      def gem
      def or
      def pass?
      def message
      def try
def depend

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-1192180673646230948?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1192180673646230948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1192180673646230948'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/05/visualizerb.html' title='visualize.rb'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-8005754489156994923</id><published>2007-05-16T22:30:00.000-07:00</published><updated>2007-05-21T09:09:06.887-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>convert.lisp</title><content type='html'>I rewrote &lt;a href="http://defcraft.org/%7Esri/hacks/ruby/convert.rb"&gt;convert.rb&lt;/a&gt; in Common Lisp; [basically it allows you to convert files from one format to another -- say, PostScript files to PDF; I need this as I sometimes work on Windows machines but want read a online papers -- this runs as a CGI program on my personal server] you can get the whole thing &lt;a href="http://defcraft.org/%7Esri/hacks/convert.lisp"&gt;here&lt;/a&gt;. It works under &lt;a href="http://www.cons.org/cmucl/"&gt;CMUCL&lt;/a&gt; version 19d.

I had forgotten how much fun it is to write programs in Common Lisp!

First, some HTML macros:
&lt;pre class="codebox"&gt;
(progn
  (defmacro html-tag (tag attributes end-tag-p &amp;body body)
    `(progn
       ,(if end-tag-p
            `(format t "&lt;~A~{ ~A=~S~}&gt;" ',tag  (list ,@attributes))
            `(format t "&lt;~A~{ ~A=~S~}/&gt;" ',tag (list ,@attributes)))
       (let ((result (multiple-value-list (progn ,@body))))
         (when (and (null (rest result)) (stringp (first result)))
           (princ (first result)))
         ,(when end-tag-p `(format t "&amp;lt;/~A&amp;gt;" ',tag))
         (values))))
         
  (defmacro do-tag (tag &amp;optional end-tag-p)
    `(defmacro ,tag (attributes &amp;body body)
       `(html-tag ,',tag ,attributes ,',end-tag-p ,@body)))


  (do-tag html t)
  (do-tag head t)
  (do-tag title t)
  (do-tag h3 t)
  (do-tag form t)
  (do-tag input)
  (do-tag b t)
  (do-tag i t)
  (do-tag br)
  (do-tag a t)
  (do-tag hr)

  )
&lt;/pre&gt;

Next, we need to decode URLs:
&lt;pre class="codebox"&gt;
(defvar *url-decoders*
  '(("24" . #\$)
    ("26" . #\&amp;)
    ("2B" . #\+)
    ("2C" . #\,)
    ("2F" . #\/)
    ("3A" . #\:)
    ("3B" . #\;)
    ("3D" . #\=)
    ("3F" . #\?)
    ("40" . #\@)
    ("20" . #\Space)
    ("22" . #\")
    ("3C" . #\&lt;)
    ("3E" . #\&gt;)
    ("23" . #\#)
    ("25" . #\%)
    ("7B" . #\{)
    ("7D" . #\})
    ("7C" . #\|)
    ("5C" . #\\)
    ("5E" . #\^)
    ("7E" . #\~)
    ("5B" . #\[)
    ("5D" . #\])
    ("60" . #\`)
    ))


(defun decode-url (url)
  (flet ((quit () (return-from decode-url nil)))
    (with-output-to-string (out)
      (with-input-from-string (in url)
        (loop (let ((char (or (read-char in nil nil) (return))))
                (if (not (char= char #\%))
                    (princ char out)
                    (let ((next (or (read-char in nil nil) (quit))))
                      (if (char= next #\%)
                          (princ #\% out)
                          (let ((next2 (or (read-char in nil nil) (quit))))
                            (princ (or (cdr (assoc (concatenate 'string
                                                                (string next)
                                                                (string next2))
                                                   *url-decoders*
                                                   :test #'string-equal))
                                       (quit))
                                   out)))))))))))
&lt;/pre&gt;


Here is CGI-WELCOME &amp; CGI-MAIN; they use the HTML macros defined above:
&lt;pre class="codebox"&gt;
(defun cgi-main ()
  (flet ((get-params ()
           (let* ((qs (cdr (assoc :query_string ext::*environment-list*)))
                  (ps (and qs (position #\&amp; qs)))
                  (parts (if ps
                             (list (subseq qs 0 ps) (subseq qs (1+ ps)))
                             (list qs)))
                  (params (mapcan (lambda (x)
                                    (let ((p (position #\= x)))
                                      (and p (list (cons (subseq x 0 p)
                                                         (subseq x (1+ p)))))))
                                  parts))
                  (url (cdr (assoc :url params :test #'string-equal)))
                  (zip-only (cdr (assoc :zip_only params :test #'string-equal))))
             (values (and url (plusp (length url)) (decode-url url))
                     (string-equal zip-only :on))))
         (print-cmds (cmd)
           ;; force-output to show user this info in their browser
           ;; while the command is still running -- works under Apache
           (princ "Running: ") (b () cmd) (br ()) (force-output))
         (print-cgi-header ()
           (let ((newline (coerce '(#\Return #\Newline) 'string)))
             (format t "Content-Type: text/html~A~A" newline newline))))

    (let ((original-dir (default-directory))
          (*shell-before* #'print-cmds)
          (url)
          (zip-only))
      (multiple-value-setq (url zip-only) (get-params))
      (print-cgi-header)
      (if (not url)
          (cgi-welcome)
          (letf (((default-directory) (tmpdir)))
            (html ()
              (head () (title () "convert.lisp"))
              (shell "wget -q '~A'" url)
              (multiple-value-bind (name error)
                  (ignore-errors (convert (or (newest)
                                              (error "couldn't download ~S" url))
                                          zip-only))
                (cond (error (princ "An error occurred: ")
                             (br ())
                             (b () (apply #'format nil
                                          (simple-condition-format-control
                                           error)
                                          (simple-condition-format-arguments
                                           error))))
                      (t (hr ())
                         (let ((base (subseq name
                                             (1+ (position #\/ name :from-end t)))))
                           (shell "cp ~A ~A/data/" base (namestring original-dir))
                           (data-file-link base)))))))))))

(defun cgi-welcome ()
  (html ()
    (head () (title () "convert.lisp"))
    (h3 () "convert.lisp -- convert files to different formats")
    (form (:method "get" :action "convert.sh")
      (princ "url: ")
      (input (:type "textfield" :name "url" :size 100))
      (princ " ")
      (input (:type "checkbox" :name "zip_only"))
      (princ "[zip only] ")
      (input (:type "submit" :value "Convert")))
    (h3 () "available converters [they are searched in order]:")
    (dolist (x *all-converter*)
      (multiple-value-bind (name cp exts doc cmds)
          (decode-converter x)
        (declare (ignore cp cmds))
        (b () (string-downcase name))
        (princ " -- ")
        (i () doc)
        (princ " [exts: ")
        (format t "~{~A~^, ~}" exts)
        (princ "]")
        (br ())))
    (h3 () "converted files [newest first]:")
    (let ((converted-files (mapcar (lambda (x) (cons (or (file-write-date x) 0) x))
                                   (ignore-errors (directory  "data/")))))
      (dolist (x (sort converted-files #'&gt; :key #'car))
        (data-file-link (cdr x))
        (br ())))
    (br ())
    (br ())
    (a (:href "convert.lisp-txt") "{mysrc}")))
    
&lt;/pre&gt;

And finally, the SHELL function that executes the different programs needed to convert files:
&lt;pre class="codebox"&gt;
(defvar *shell-before*)

(defun shell (cmd &amp;rest args)
  (let ((cmd (apply #'format nil cmd args)))
    (when (boundp '*shell-before*) (funcall *shell-before* cmd))
    (ext:run-program "/bin/bash"
                     (list "-c" cmd))))
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-8005754489156994923?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8005754489156994923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8005754489156994923'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/05/convertlisp.html' title='convert.lisp'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4664344298959880825</id><published>2007-05-07T23:45:00.000-07:00</published><updated>2007-05-07T23:51:31.306-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Dancing Links in Python</title><content type='html'>Last December I was reading &lt;a href="http://www-cs-faculty.stanford.edu/~knuth/"&gt;Knuth&lt;/a&gt;'s &lt;a href="http://www-cs-faculty.stanford.edu/~uno/papers/dancing-color.ps.gz"&gt;Dancing Links&lt;/a&gt; paper and decided to implement the &lt;a href="http://en.wikipedia.org/wiki/Algorithm_X"&gt;Algorithm X&lt;/a&gt; in Python.
&lt;br/&gt;&lt;br/&gt;
Here is the description of Algorithm X from Wikipedia:
&lt;blockquote&gt;...is a recursive, nondeterministic, depth-first, brute-force algorithm that finds all solutions to the exact cover problem represented by a matrix A consisting of 0s and 1s.&lt;/blockquote&gt;
&lt;br/&gt;&lt;br/&gt;
It can be downloaded &lt;a href="http://defcraft.org/~sri/hacks/dancing_links.py"&gt;here&lt;/a&gt;.

&lt;pre class="codebox"&gt;
# What is the matrix? It is a helper class
# for exact cover below.
class Matrix:
    def __init__(self, list_of_lists):
        self.m = [list_elt[:] for list_elt in list_of_lists]
        self.unique = object()

    def copy(self):
        new = Matrix(self.m)
        for r in new.m:
            for i in range(len(r)):
                if r[i] == self.unique:
                    r[i] = new.unique
        return new
    
    def delcol(self, i):
        for r in self.m:
            r[i] = self.unique

    def delrow(self, i):
        row = self.m[i]
        for j in range(len(row)):
            row[j] = self.unique

    def empty(self):
        for r in self.m:
            for x in r:
                if x != self.unique:
                    return False
        return True

    # Select first column with lowest number of 1s.
    # Also, returns the number of 1s found in the
    # column.
    def selcol(self):
        i = -1
        s = -1
        for colidx in range(len(self.m[0])):
            colitems = [r[colidx] for r in self.m]
            if all(x==self.unique for x in colitems):
                continue
            t = colitems.count(1)
            if s == -1 or t &lt; s:
                s = t
                i = colidx
        return i, s
&lt;/pre&gt;

&lt;pre class="codebox"&gt;
# == Algorithm X  ======================================================
                
class ExactCover:
    def X(self, matrix):
        if matrix.empty():
            return []

        result = self.__X(matrix.copy())
        if result:
            all_answers = []
            for answer in result:
                all_answers.append([matrix.m[rowidx]
                                    for rowidx in answer])
            return all_answers
        else:
            return []

    def __X(self, matrix):
        # 1. Select 1st column with lowest
        #    number of 0s.
        c, s = matrix.selcol()
        if s == 0:
            return []

        # 2. Pick rows that have 1s in the
        #    above column.
        possible_rows = [(i, r) for (i, r) in enumerate(matrix.m) if r[c] == 1]
        random.shuffle(possible_rows)
        
        answers = []
        # 3. For each such row:
        for rowidx, r in possible_rows:
            new = matrix.copy()

            for i, item in enumerate(r):
                # - pick columns that have 1s
                #   in them
                # 4. For each such col:
                if item == 1:
                    for j, item2 in enumerate([r[i] for r in new.m]):
                        # - delete rows that have a 1
                        #   in that column
                        if item2 == 1:
                            new.delrow(j)
                    # - delete that column
                    #   [this was a bug before;
                    #    it used to be above the
                    #    for loop right after the
                    #    "item == 1" expr]
                    new.delcol(i)

            if new.empty():
                answers.append([rowidx])
            else:
                # - recur on the sub-matrix
                result = self.__X(new)
                for x in result:
                    x.append(rowidx)
                    answers.append(x)

        return answers

        
# == Tests ==========================================

def test_exact_cover():
     e =  [[1, 0, 0, 1, 0, 0, 1],
           [1, 0, 0, 1, 0, 0, 0],
           [0, 0, 0, 1, 1, 0, 1],
           [0, 0, 1, 0, 1, 1, 0],
           [0, 1, 1, 0, 0, 1, 1],
           [0, 1, 0, 0, 0, 0, 1]]
     m = Matrix(e)
     res = ExactCover().X(m)
     if res == [[[0, 1, 0, 0, 0, 0, 1],
                 [0, 0, 1, 0, 1, 1, 0],
                 [1, 0, 0, 1, 0, 0, 0]]]:
         print "test pass"
     else:
         print "test fail"
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4664344298959880825?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4664344298959880825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4664344298959880825'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/05/dancing-links-in-python.html' title='Dancing Links in Python'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4065342359618359511</id><published>2007-04-23T14:01:00.000-07:00</published><updated>2007-04-23T15:18:35.529-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>N-based Python list</title><content type='html'>Solving &lt;a href="http://www.answermysearches.com/python-subclassing-list-to-make-it-n-based/251/"&gt;http://www.answermysearches.com/python-subclassing-list-to-make-it-n-based/251/&lt;/a&gt;
(with some light testing)

&lt;pre class="codebox"&gt;
class n_based_list(list):
    def __init__(self, startidx, items):
        self.start = startidx
        list.__init__(self, items)

    def idx(self, i):
        return i - self.start

    def insert(self, i, x):
        return list.insert(self, self.idx(i), x)

    def pop(self, i):
        return list.pop(self, self.idx(i))

    def __getslice__(self, i, j):
        return list.__getslice__(self, self.idx(i), j)

    def _handle_slice(self, s):
        return slice(self.idx(s.start or self.start),
                     s.stop,
                     s.step)

    def __getitem__(self, i):
        if isinstance(i, slice):
            return list.__getitem__(self, self._handle_slice(i))
        return list.__getitem__(self, self.idx(i))

    def __setitem__(self, i, x):
        if isinstance(i, slice):
            return list.__setitem__(self, self.handle_slice(i), x)
        return list.__setitem__(self, self.idx(i), x)

    def __delitem__(self, i):
        if isinstance(i, slice):
            return list.__delitem__(self, self._handle_slice(i))
        return list.__delitem__(self, self.idx(i))
    
    def enumerate(self):
        for i, elt in enumerate(self):
            yield i+self.start, elt
            
def test_n_based_list():
    l = n_based_list(1, ['a', 'b', 'c', 'd'])
    assert l[1] == 'a'
    assert l[0] == 'd' # yuck!
    assert l[2] == 'b'
    assert l[3] == 'c'
    assert l[4] == 'd'

    assert l.pop(1) == 'a'
    assert l == ['b', 'c', 'd']
    l.insert(1, 'a')
    assert l[1] == 'a'

    assert l[1:3] == ['a', 'b', 'c']
    assert l[1::2] == ['a', 'c']
    del l[::2]
    assert l == ['b', 'd']
    new_l = n_based_list(1, ['a', 'b', 'c', 'd'])
    assert list(new_l.enumerate()) == [(1, 'd'),
                                       (2, 'a'),
                                       (3, 'b'),
                                       (4, 'c')]
           

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4065342359618359511?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4065342359618359511'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4065342359618359511'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/04/n-based-python-list.html' title='N-based Python list'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-6042252148155068655</id><published>2007-04-12T13:28:00.000-07:00</published><updated>2007-04-12T13:29:23.949-07:00</updated><title type='text'>a merge problem</title><content type='html'>from here: &lt;a href="http://blog.dowski.com/2007/04/12/a-sorting-problem/"&gt;http://blog.dowski.com/2007/04/12/a-sorting-problem/&lt;/a&gt;

&lt;pre class="codebox"&gt;
from collections import defaultdict

def my_order(ordered, others):
    tmp = defaultdict(list)
    losers = []
    # process others so that,
    # 'id_new', 'id_old' become
    # tmp['id'] = ['id_new', 'id_old']
    for o in others:
        p = o.rfind("_")
        if p == -1:
            losers.append(o)
        else:
            # if o is 'id_new',
            # o[:p] will be 'id'
            tmp[o[:p]].append(o)
    final = []
    for o in ordered:
        final.append(o)
        if o in tmp:
            final.extend(tmp[o])
    return final + losers

my_order(['id', 'age', 'zzyzx', 'bar', 'spam_eggs'],
         ['id_old', 'id_new', 'bar_foo', 'spam_eggs_ham'])

gives
['id', 'id_old', 'id_new', 'age', 'zzyzx',
 'bar', 'bar_foo', 'spam_eggs', 'spam_eggs_ham']

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-6042252148155068655?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6042252148155068655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/6042252148155068655'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/04/merge-problem.html' title='a merge problem'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-8845024646459400670</id><published>2007-03-18T17:27:00.000-07:00</published><updated>2007-04-04T09:50:53.231-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Fluid Strings</title><content type='html'>I just completed a piece of software &amp;mdash; one part of the software sends text messages to cell phones. Each text message consists of several fields. And each field has a maximum limit on how long it can be. So if a field is longer than its limit, then it is cutoff. However, if the field smaller than its limit, then all the other fields should take up space that this field "gives up" &amp;mdash; so, other fields can become longer than their limits in the final output. Here is what I did:

&lt;pre class="codebox"&gt;
class FluidString(object):
    
    def __init__(self, actual, limit, prefix="", suffix=""):
        self.actual = actual
        self.limit = limit
        self.prefix = prefix
        self.suffix = suffix

    def increase_limit_by(self, amt):
        self.limit += amt

    def __str__(self):
        # adding newline is a hack, specific for my app,
        # where I want each fluid string to be
        # contained in a seperate line

        t = len(self.prefix) + len(self.suffix)
        if self.limit &lt; t:
            return self.actual[:self.limit]
        
        s = self.actual[:self.limit-1-t]
        return self.prefix + s + self.suffix + "\n"


    # returns non-negative integer:
    def chars_left_over(self):
        return max(self.limit - len(str(self)), 0)
&lt;/pre&gt;
&lt;br/&gt;
Fluid strings are assembled by containers:
&lt;pre class="codebox"&gt;
# right now just fits pieces fluidly;
# if any piece underflows, other pieces
# evenly get what's left over.

class Container(object):
    
    def __init__(self, *items):
        self.strings = list(items)
        
    def add(self, fs):
        self.strings.append(fs)
        
    # unused:
    def on_underflow_of(self, target, *fs_pairs):
        pass
    
    def render(self):
        # find fluid strings that are underflowing.
        # split all those free spaces among strings that
        # are likely to overflow.

        anyleft = [x.chars_left_over() for x in self.strings]
        freespace = sum(anyleft)
        
        # how many to split freespace with:
        # `if not x': it means that the fluid string
        # will likely overflow. so split space among
        # those likely to overflow
        count = anyleft.count(0) #sum(1 for i in anyleft if i==0)
        
        if freespace and count:
            amount = freespace / count
            for i, x in enumerate(self.strings):
                if not anyleft[i]:
                    x.increase_limit_by(amount)

        final = "".join(str(x) for x in self.strings)
        #assert len(final) == sum(x.limit for x in self.strings)
        return final

    @staticmethod
    def test():
        c = Container()
        c.add(FluidString("01234567890123456789", 10))
        c.add(FluidString("asdf", 20))
        c.add(FluidString("hello world how are you", 10))
        return c.render()
&lt;/pre&gt;
&lt;br/&gt;
Here is an usage sample (it is also above):
&lt;pre class="codebox"&gt;
    def test():
        c = Container()
        c.add(FluidString("01234567890123456789", 10))
        c.add(FluidString("asdf", 20))
        c.add(FluidString("hello world how are you", 10))
        return c.render()
&lt;/pre&gt;
The output is:
&lt;pre class="codebox"&gt;
01234567890123456
asdf
hello world how a
[newline]
&lt;/pre&gt;
(Note how the first &amp; third FluidString added, shows more than its limit allows it &amp;mdash; extra 7 characters each + 2 newlines.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-8845024646459400670?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8845024646459400670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8845024646459400670'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/03/fluid-strings.html' title='Fluid Strings'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-1822367421323645130</id><published>2007-02-24T18:09:00.000-07:00</published><updated>2007-02-24T18:18:54.044-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='notes'/><title type='text'>The Computer Revolution Hasn't Happened Yet</title><content type='html'>Notes of &lt;a href="http://video.google.com/videoplay?docid=-2950949730059754521"&gt;Alan Kay's 1997 OOPSLA talk&lt;/a&gt; via &lt;a href="http://lambda-the-ultimate.org/"&gt;Lambda-the-Ultimate&lt;/a&gt;.
&lt;br/&gt;&lt;br/&gt;
&lt;a href="http://www.iam.unibe.ch/~denker/AlanKayOOP.html"&gt;Alan Kay On OOP&lt;/a&gt;


&lt;p&gt;
As things become more and more complex,&lt;br/&gt;
the architecture will dominate material.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
Learning is an act of creation.&lt;br/&gt;
Something happens to you that&lt;br/&gt;
wasn't there before.&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
When encountering a creative, novel idea.&lt;br/&gt;
Reaction by the user.&lt;br/&gt;
Metaphor
&lt;/p&gt;
&lt;p&gt;
Joke -- ha ha.&lt;br/&gt;
Science -- Aha!&lt;br/&gt;
Art -- ahhh...

&lt;/p&gt;
&lt;p&gt;
You need to have something&lt;br/&gt;
blue, to have blue thoughts.
&lt;/p&gt;
&lt;p&gt;
23:00
&lt;br/&gt;

HTML pre-supposes that there&lt;br/&gt;
should be a browser that should&lt;br/&gt;
understand its format.&lt;br/&gt;
(worst ideas since ms-dos!)
&lt;br/&gt;
+ He is talking about executable&lt;br/&gt;
programs? Like lisp images.
&lt;br/&gt;
You should read it in. It should&lt;br/&gt;
travel with the things it needs.
&lt;/p&gt;
&lt;p&gt;

Why study of Biology is interesting?&lt;br/&gt;
Build a dog house. Now build something&lt;br/&gt;
similar, but 100 times larger.&lt;br/&gt;
Propotions will be unwieldly and&lt;br/&gt;
the thing collapes.
&lt;br/&gt;
Not so for cells.&lt;br/&gt;
They can even grow by factors&lt;br/&gt;
of 1 millions. And so how do&lt;br/&gt;
they do this is important?&lt;br/&gt;
Because we want to build&lt;br/&gt;
complex computer systems -- &lt;br/&gt;
which we haven't been able&lt;br/&gt;
to do.
&lt;/p&gt;
&lt;p&gt;
39:00&lt;br/&gt;
Object can act as anything.&lt;br/&gt;
So they encapsulate a computer.&lt;br/&gt;
Useful: take a powerful thing&lt;br/&gt;
and not lose it but partitioning&lt;br/&gt;
it up.&lt;br/&gt;
[Java, C++ think that they are helping&lt;br/&gt;
the programmer by making this new&lt;br/&gt;
thing (oop) look like the old thing,&lt;br/&gt;
but they are hurting the programmer,&lt;br/&gt;
but making it difficult for the programmer&lt;br/&gt;
to understand what's really powerful&lt;br/&gt;
about this metaphor.]
&lt;/p&gt;
&lt;p&gt;
45:00&lt;br/&gt;
Building Complex Systems.
&lt;/p&gt;
&lt;p&gt;
59:00
We still don't know how to design,&lt;br/&gt;
build systems.
&lt;/p&gt;
&lt;p&gt;
Let's not make what we don't know&lt;br/&gt;
into a religion!
&lt;/p&gt;
&lt;p&gt;
We need to constantly think, think and&lt;br/&gt;
think about what's important.&lt;br/&gt;
And we have to our systems let us get&lt;br/&gt;
to the next levels of abstractions&lt;br/&gt;
as we come to them. (Earlier he&lt;br/&gt;
was talking about how there were&lt;br/&gt;
many different implementation of&lt;br/&gt;
Smalltalk when at Xerox. The old&lt;br/&gt;
implementation were good at bootstrapping&lt;br/&gt;
new implementations -- these new&lt;br/&gt;
implementations were built to support&lt;br/&gt;
the new abstractions Alan and his&lt;br/&gt;
collegues came to know about. And I&lt;br/&gt;
guess the dynamicsm of Smalltalk made&lt;br/&gt;
this possible.)
&lt;/p&gt;
&lt;p&gt;
Squeak -- not an attempt to give the world&lt;br/&gt;
a free Smalltalk -- but an attempt to give&lt;br/&gt;
the world a bootstrapping mechanism much&lt;br/&gt;
better that smalltalk. SO when you play&lt;br/&gt;
with squeak -- think of how you can&lt;br/&gt;
obselete the damn thing!&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
Look for blue thoughts.&lt;br/&gt;
Play your system grand than what they&lt;br/&gt;
seem to be right now.&lt;br/&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-1822367421323645130?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1822367421323645130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/1822367421323645130'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/02/notes-of-alan-kays-1997-oopsla-talk.html' title='The Computer Revolution Hasn&apos;t Happened Yet'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-2672540298258385786</id><published>2007-02-11T21:09:00.000-07:00</published><updated>2007-02-11T21:09:25.069-07:00</updated><title type='text'>New import</title><content type='html'>OK, imported all posts from &lt;a href="http://89seasons.blogspot.com"&gt;http://89seasons.blogspot.com&lt;/a&gt; &amp;mdash; hopefully nothing broke.

If it did, please feel free to keep both the pieces!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-2672540298258385786?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2672540298258385786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2672540298258385786'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/02/new-import.html' title='New import'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-664331388839219731</id><published>2006-12-09T15:01:00.000-07:00</published><updated>2007-02-11T21:07:06.280-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>orange4.py -- an interpreter for a Lisp like lang in Python</title><content type='html'>&lt;blockquote&gt;&lt;a href="http://defcraft.org/~sri/hacks/orange4.py"&gt;Orange4.py&lt;/a&gt; [&lt;a href="http://defcraft.org/~sri/hacks/orange4.py.txt"&gt;as text&lt;/a&gt;] implements a &lt;a href="http://www.lisp.org/"&gt;Lisp&lt;/a&gt; like language in &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt;. I make use of Python tuples to represent the source code. Here is the &lt;a href="http://www.ece.uc.edu/~franco/C511/html/Scheme/ycomb.html"&gt;Y Combinator&lt;/a&gt;:&lt;/blockquote&gt;

&lt;pre class="codebox"&gt;
(using('ycomb x proc arg fact fnarg n'),
 (let, ((ycomb, (olambda, (x,),
                 ((olambda, (proc,),
                    (x, (olambda, (arg,), ((proc, proc), arg)))),
                  (olambda, (proc,),
                    (x, (olambda, (arg,), ((proc, proc), arg))))))),),
  (let, ((fact, (olambda, (fnarg,),
                  (olambda, (n,),
                    (oif, (eq, n, 0),
                          1,
                          (multiply, n,
                                     (fnarg, (minus, n, 1))))))),),
   (pr, "hi"),
   (pr, ((ycomb, fact), 10)),
   ((ycomb, fact), 10))))
&lt;/pre&gt;

&lt;blockquote&gt;Yeah, the syntax is &lt;span style="font-weight:bold;"&gt;UGLY&lt;/span&gt;, and to make this tuples-as-source work (since Python would complain about variables in "&lt;span style="font-weight:bold;"&gt;(olambda, (b, c, d), ...)&lt;/span&gt;", you have to say something like, "&lt;span style="font-weight:bold;"&gt;(using('b c d'), (olambda, (b, c, d), ...)&lt;/span&gt;". Also, you need to be careful about singleton tuples in Python: so you can't write "&lt;span style="font-weight:bold;"&gt;(let, ((a, 20)), ...)&lt;/span&gt;"; you need to say: "&lt;span style="font-weight:bold;"&gt;(let, ((a, 20),), ...)&lt;/span&gt;".
&lt;br/&gt;&lt;br/&gt;
&lt;span style="font-style:italic;"&gt;using&lt;/span&gt; is defined as:&lt;/blockquote&gt;

&lt;pre class="codebox"&gt;
class using:
    def __init__(self, string):
        for name in string.split():
            if name in globals():
                print "Warning: `%s' already defined, ignoring it" % name
            else:
                globals()[name] = var(name)

&lt;/pre&gt;

&lt;blockquote&gt;And here are EVAL and APPLY, named OEVAL and OAPPLY so that they don't conflict with the Python builtins of the same name:&lt;/blockquote&gt;

&lt;pre class="codebox"&gt;
def oeval(x, env=None):
    if trace: print 'oeval', x, env

    if isinstance(x, var):
        return env_lookup(x, env)
    elif not isinstance(x, tuple):
        return x

    if isinstance(x[0], using):
        x = x[1]

    fn   = x[0]
    args = x[1:]

    if fn == OIF:
        if oeval(args[0], env) == NIL:
            return oeval(args[2], env)
        else:
            return oeval(args[1], env)

    elif fn == OLAMBDA:
        return (CLOSURE, args[0], args[1:], env)

    elif fn == LET:
        bindings = args[0]
        newenv = dict((var.name, oeval(val, env))
                      for (var, val) in bindings)

        return oevalis(args[1:], [newenv, env])

    else: # function application
        # global env is the python global env,
        # so we don't need to evaluate fn (i think).
        return oapply(oeval(fn, env),
                      tuple(oeval(arg, env) for arg in args))
&lt;/pre&gt;

&lt;pre class="codebox"&gt;
# since we are applying fns, args are evalled
def oapply(fn, args):
    def err(type):
        error("%s %s, %s" % (
            type,
            (fn.name if isinstance(fn, var) else fn),
            args))

    if not isinstance(fn, tuple):
        if fn == GT:
            if args[0] &gt; args[1]:
                return TRUE
            return NIL

        elif fn == PR:
            print args[0]
            return NIL

        elif fn == PLUS:
            return args[0] + args[1]

        elif fn == MINUS:
            return args[0] - args[1]

        elif fn == EQ:
            # args should just be numbers
            if args[0] == args[1]:
                return TRUE
            return NIL

        elif fn == MULTIPLY:
            return args[0] * args[1]

        else:
            err("unknown function")

    # user-defined functions:
    elif fn[0] == CLOSURE:
        if trace: print 'calling closure', fn, args

        formal_params, body, env_when_defined = fn[1:]
        actual_params = args

        if len(formal_params) != len(actual_params):
            err("wrong number of args")
        newenv = dict(zip((x.name for x in formal_params),
                          actual_params))
        # lexical scoping
        return oevalis(body, [newenv, env_when_defined])

        # return oevalis(body, [newenv, env])
        # the above specifies dynamic scoping (i think!)
        # env, should be an env passed
        # to this oapply fn.

    else:
        err("unknown function")

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-664331388839219731?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/664331388839219731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/664331388839219731'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/02/orange4py-interpreter-for-lisp-like.html' title='orange4.py -- an interpreter for a Lisp like lang in Python'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-7658025661332009429</id><published>2006-11-09T21:01:00.000-07:00</published><updated>2007-02-11T21:06:54.242-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><title type='text'>readable MD5</title><content type='html'>I've written an implementation of the &lt;a href="http://www.ietf.org/rfc/rfc1321.txt"&gt;MD5 algorithm&lt;/a&gt;  mainly for human consumption. Most implementations that I've seen, seem to derive from the RFC's sample implementation, which is optimized for performance and so isn't that readable.
&lt;br/&gt;&lt;br/&gt;
&lt;a href="http://defcraft.org/~sri/hacks/readable-md5.lisp"&gt;readable-md5.lisp&lt;/a&gt; [&lt;a href="http://defcraft.org/~sri/hacks/readable-md5.lisp.txt"&gt;as text&lt;/a&gt;] [its written in Common Lisp and has been tested with CMUCL and CLisp]
&lt;br/&gt;
&lt;blockquote&gt;&lt;span style="font-weight:bold;"&gt;...programs must be written for people to read, and only incidentally for machines to execute.&lt;/span&gt;&lt;br/&gt;
&amp;mdash; &lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-7.html"&gt;Structure and Interpretation of Computer Programs&lt;/a&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-7658025661332009429?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7658025661332009429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/7658025661332009429'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/02/readable-md5.html' title='readable MD5'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-2452625569946109814</id><published>2006-10-28T13:05:00.000-07:00</published><updated>2007-02-11T21:05:38.144-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>My first Ruby program</title><content type='html'>&lt;p&gt;I decided to learn Ruby and Rails — now I need to get books on both (damn that DHH and his contagious enthusiasm)
&lt;/p&gt;
&lt;p&gt;
Below are some snippets from my first Ruby program: &lt;a href="http://defcraft.org/%7Esri/hacks/ruby/convert.rb"&gt;convert.rb&lt;/a&gt;. It is a CGI program, that converts PostScript, TeX, CWEB and a couple of other formats to PDF.  It also converts .tar.gz, .tar.bz2 and other compressed files to .zip. 
&lt;/p&gt;
&lt;p&gt;[Note: I wrote this program flipping back and forth between the PixAxe1 and a bunch of other online resources — so forgive me if it isn't in the spirit of Ruby.]
&lt;/p&gt;
&lt;p&gt;Ruby blocks are cool!!!&lt;/p&gt;

&lt;pre class="codebox"&gt;
def ignore_errors &amp;block
  begin
    block.call
  rescue Exception =&amp;gt; e
    e
  end
end

def with_tmpdir &amp;block
  result = nil
  original = Dir.pwd
  tmp = tmpname # creates a temporary name (not safe)
  begin
    Dir.mkdir tmp
    Dir.chdir tmp
    result = block.call original
  ensure
    Dir.chdir original
  end
  FileUtils.rm_rf tmp
  result
end
&lt;/pre&gt;

and it is quiet easy to create DSLs:

&lt;pre class="codebox"&gt;
# converters operate like so:
# 3 args: first, a symbol naming the converter;
# second, a regexp that if matched the third arg
# is executed: which is a block that takes one
# argument -- a local filename
# the converter should return true or nil:
# true to continue and try other converters;
# nil to return -- as this is the final one.

defconverter(:ps, /\.ps$/) { | x |
  sh "ps2pdf #{x}"
  nil
}

defconverter(:cweb, /\.w$/) { | x |
  sh "cweave #{x} - #{x}.tex"
  sh "tex #{x}.tex"
  sh "dvips #{x}.dvi"
  sh "ps2pdf #{x}.ps"
  nil
}
&lt;/pre&gt;

Finally, CGI.rb's HTML output facility make the code elegant (I wish that, optionally, you could output to a stream...)

&lt;pre class="codebox"&gt;
  cgi.out {
    cgi.html("PRETTY" =&amp;gt; " ") {
      cgi.head { cgi.title { 'convert.rb' } } +
      cgi.body {
        cgi.h3 { 'convert.rb — convert file to PDF or ZIP' } +
        cgi.form('get', $0) {
        cgi.b { 'url:' } +
        cgi.text_field('url', '', 150) + ' ' +
        cgi.submit + cgi.br +
        cgi.checkbox('zipitup') + ' zip it up? ' +
        cgi.small { '[with this turned on, you can convert
                     unix archive formats (like .tar.gz, .tar.bz2,
                     ...) to .zip format]' }

      ...
      ...
      ...
      [snipped]
&lt;/pre&gt;

Here are some initial thoughts:
&lt;ul&gt;&lt;li&gt;I was surprised at how easily and quickly I was able to develop the program &lt;/li&gt;

&lt;li&gt;calling methods (those that don't take args and those that take a single arg) without parenthesis is quiet refreshing:
&lt;br/&gt;
(Before this, looking at Ruby from the "outside", this convention was disturbing — "How do I pass a function to another function" — but I didn't encounter that problem with this program because it seems to me that you pass in closures (blocks) to other functions...)
&lt;br/&gt;
&lt;br/&gt;compare &lt;span style="font-weight: bold;"&gt;method.to_a.to_s&lt;/span&gt; to &lt;span style="font-weight: bold;"&gt;method.to_a().to_s()&lt;/span&gt;
&lt;br/&gt;&lt;b&gt;sh "rpm2cpio #{x} | cpio -dimv --no-absolute-filenames"&lt;/b&gt;
&lt;/li&gt;&lt;li&gt;love the short, nicely named methods: &lt;b&gt;FileUtils.rm_rf tmp&lt;/b&gt;&lt;/li&gt;&lt;li&gt;ability to specify integer as &lt;span style="font-weight: bold;"&gt;100_000_000&lt;/span&gt; is nice&lt;/li&gt;

&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-2452625569946109814?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2452625569946109814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/2452625569946109814'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/02/my-first-ruby-program.html' title='My first Ruby program'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-4682599660902742314</id><published>2006-10-15T13:59:00.000-07:00</published><updated>2007-02-11T21:04:37.569-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>flowering.py</title><content type='html'>I've been playing with a Paint-like program on my 6600 (with Python for Series 60). The cool things is after I paint a picture, I can take a screenshot of it and use that image as the background for my phone. To paint the second pic (the first one is similar), you first &lt;i&gt;gravitate&lt;/i&gt; (bounce ball), then &lt;i&gt;pretend you are Bob Ross&lt;/i&gt; (hit zero key) (&lt;small&gt;remember Bob Ross's paintings? occasionally, before starting, he would put an oval cut out over the actual canvas he was painting on &amp;mdash; after he was done, he would remove the cutout and all of a sudden the painting itself would be oval shaped..&lt;/small&gt;), then &lt;i&gt;realize that you really don't need to be him&lt;/i&gt; (hit zero key again) and finally &lt;i&gt;start gravitating&lt;/i&gt; once again. Here are some &lt;i&gt;flowerings&lt;/i&gt;:


&lt;div align="center"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/7722/742037074390692/1600/screenshot4.jpg"&gt;
&lt;img style="margin: 0pt 10px 10px 0pt;  cursor: pointer;" src="http://photos1.blogger.com/blogger2/7722/742037074390692/400/screenshot4.jpg" alt="" border="0" /&gt;&lt;/a&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/7722/742037074390692/1600/screenshot3.jpg"&gt;
&lt;img style="margin: 0pt 10px 10px 0pt;  cursor: pointer;" src="http://photos1.blogger.com/blogger2/7722/742037074390692/400/screenshot3.jpg" alt="" border="0" /&gt;&lt;/a&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/7722/742037074390692/1600/screenshot2.jpg"&gt;
&lt;img style="margin: 0pt 10px 10px 0pt;  cursor: pointer;" src="http://photos1.blogger.com/blogger2/7722/742037074390692/400/screenshot2.jpg" alt="" border="0" /&gt;&lt;/a&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/7722/742037074390692/1600/screenshot.jpg"&gt;
&lt;img style="margin: 0pt 10px 10px 0pt;  cursor: pointer;" src="http://photos1.blogger.com/blogger2/7722/742037074390692/400/screenshot.jpg" alt="" border="0" /&gt;&lt;/a&gt;
&lt;/div&gt;

The program, &lt;b&gt;flowering.py&lt;/b&gt; isn't well polished:
&lt;pre class="codebox"&gt;
# sri, oct 15, 2006
# under mit license
# used Nokia's ball.py example as reference implementation;
# Menu Key: allows you to select type of brush
# Exit: exit app
# Hash Key (#): take a pic
# Star Key (*): for fun!

import appuifw, graphics, e32
from key_codes import *

class Keyboard:
    def __init__(self):
        self.state = {}
        self.downs = {}

    def handle_event(self, event):
        code = event.get("scancode", False)
        if event["type"] == appuifw.EEventKeyDown:
            if not self.is_down(code):
                self.downs[code] = self.downs.get(code, 0) + 1
            self.state[code] = 1
        elif event["type"] == appuifw.EEventKeyUp:
            self.state[code] = 0

    def is_down(self, scancode):
        return self.state.get(scancode, 0)

    def pressed(self, scancode):
        if self.downs.get(scancode, 0):
            self.downs[scancode] -= 1
            return True
        return False

# --------------------------------------------------------------------

gravitate = False  # brush it a  bouncing ball
justpaint = False  # brush is a brush, OK?

def do_gravitate():
    global gravitate, justpaint
    gravitate = True
    justpaint = False
def do_justpaint():
    global justpaint, gravitate
    justpaint = True
    gravitate = False

appuifw.app.menu = [
    (u"Gravitate", do_gravitate),
    (u"Just paint", do_justpaint)
    ]
keyboard = Keyboard()

running = True
def quit():
    global running
    running = False
appuifw.app.exit_key_handler = quit

appuifw.app.screen = "full"
appuifw.app.body = c = appuifw.Canvas(
    event_callback=keyboard.handle_event)

call_me_bob_ross = 0
radius = min(c.size)/2
xcenter, ycenter = c.size[0]/2, c.size[1]/2

topleft = (xcenter-radius,
           ycenter-radius)
bottomright = (xcenter+radius,
               ycenter+radius)

# ball stuff:
position = [0, 0]
velocity = [0, 0]
acceleration = 0.05
gravity = 0.03

c_size = c.size
#oldposition = position

# ball color stuff:
coloridx = 0
allcolors = []
tmp = (0, 32, 64, 128, 255)
for r in tmp:
    for g in tmp:
        for b in tmp:
            allcolors.append((r, g, b))
allcolors_len = len(allcolors)

# --------------------------------------------------------------------

while running:
    coloridx += 1
    if coloridx &gt;= allcolors_len:
        coloridx = 0

    c.point(position,
            allcolors[coloridx],
            width=15)

    if call_me_bob_ross%2 != 0:
        c.ellipse(((0,0), c.size),
                  outline=(255, 0, 0), # red,
                  width=1)

    e32.ao_yield()

    if gravitate:
        # -----------------------------------------------------
        velocity[0] *= 0.999
        velocity[1] *= 0.999
        velocity[1] += gravity
        oldposition = position
        position[0] += velocity[0]
        position[1] += velocity[1]

        if position[0] &gt; c_size[0]:
            position[0] = c_size[0] - (position[0] - c_size[0])
            velocity[0] = -1.00 * velocity[0]
            velocity[1] =  1.00 * velocity[1]
        if position[0] &lt; 0:
            position[0] = -position[0]
            velocity[0] = -1.00 * velocity[0]
            velocity[1] =  1.00 * velocity[1]
        if position[1] &gt; c_size[1]:
            position[1] = c_size[1] - (position[1] - c_size[1])
            velocity[0] =  1.00 * velocity[0]
            velocity[1] = -1.00 * velocity[1]
        if position[1] &lt; 0:
            position[1] = -position[1]
            velocity[0] =  1.00 * velocity[0]
            velocity[1] = -1.00 * velocity[1]

        if keyboard.is_down(EScancodeLeftArrow):
            velocity[0] -= acceleration
        if keyboard.is_down(EScancodeRightArrow):
            velocity[0] += acceleration
        if keyboard.is_down(EScancodeDownArrow):
            velocity[1] += acceleration
        if keyboard.is_down(EScancodeUpArrow):
            velocity[1] -= acceleration
        # -----------------------------------------------------
    else:
        # just paint
        if keyboard.is_down(EScancodeLeftArrow):
            position[0] -= 1
        if keyboard.is_down(EScancodeRightArrow):
            position[0] += 1
        if keyboard.is_down(EScancodeDownArrow):
            position[1] += 1
        if keyboard.is_down(EScancodeUpArrow):
            position[1] -= 1

    # common actions:
    if keyboard.pressed(EScancodeHash):
        if call_me_bob_ross%2 != 0:
            c.ellipse(((0,0), c.size),
                      outline=(255, 255, 255),
                      width=100)
        img = graphics.screenshot()
        img = img.resize((174, 143), keepaspect=1)
        img.save(u"E:\\screenshot.jpg")
    elif keyboard.pressed(EScancodeStar):
        c.clear()
    elif keyboard.pressed(EScancode0):
        call_me_bob_ross += 1


&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-4682599660902742314?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4682599660902742314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/4682599660902742314'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/02/floweringpy.html' title='flowering.py'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-3129114374263606505</id><published>2006-10-10T17:58:00.000-07:00</published><updated>2007-02-11T21:03:59.881-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Sierpinski — in ASCII, in Python</title><content type='html'>I wrote this in the fall of 2004 (I was taking a class with one of the best teachers I've ever had and she gave this as a bonus on an exam &amp;mdash; this fractal was on her t-shirt and she asked its name).
(this works under python 2.4)

&lt;pre class="codebox"&gt;
&amp;gt;&amp;gt;&amp;gt; print_triangle(get_sierpinski(5))

                               /\
                              /__\
                             /\  /\
                            /__\/__\
                           /\      /\
                          /__\    /__\
                         /\  /\  /\  /\
                        /__\/__\/__\/__\
                       /\              /\
                      /__\            /__\
                     /\  /\          /\  /\
                    /__\/__\        /__\/__\
                   /\      /\      /\      /\
                  /__\    /__\    /__\    /__\
                 /\  /\  /\  /\  /\  /\  /\  /\
                /__\/__\/__\/__\/__\/__\/__\/__\
               /\                              /\
              /__\                            /__\
             /\  /\                          /\  /\
            /__\/__\                        /__\/__\
           /\      /\                      /\      /\
          /__\    /__\                    /__\    /__\
         /\  /\  /\  /\                  /\  /\  /\  /\
        /__\/__\/__\/__\                /__\/__\/__\/__\
       /\              /\              /\              /\
      /__\            /__\            /__\            /__\
     /\  /\          /\  /\          /\  /\          /\  /\
    /__\/__\        /__\/__\        /__\/__\        /__\/__\
   /\      /\      /\      /\      /\      /\      /\      /\
  /__\    /__\    /__\    /__\    /__\    /__\    /__\    /__\
 /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\
/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\/__\


# under mit license
#! /usr/bin/env python
#
# N = 4:
#                /\
#               /__\
#              /\  /\
#             /__\/__\
#            /\      /\
#           /__\    /  \
#          /\  /\  /\  /\
#         /__\/__\/__\/__\
#        /\              /\
#       /__\            /__\
#      /\  /\          /\  /\
#     /__\/__\        /__\/__\
#    /\      /\      /\      /\
#   /__\    /  \    /__\    /__\
#  /\  /\  /\  /\  /\  /\  /\  /\
# /__\/__\/__\/__\/__\/__\/__\/__\
#
# N = 3:
#        /\
#       /__\
#      /\  /\
#     /__\/__\
#    /\      /\
#   /__\    /__\
#  /\  /\  /\  /\
# /__\/__\/__\/__\
#
# N = 2:
#    /\
#   /__\
#  /\  /\
# /__\/__\
#
# N = 1:
#  /\
# /__\
#
# N = 0: (trivial case)
#
import sys

# returns a list of lines where
# each line contains a 2-element list:
# a character and a position
def get_sierpinski(n):
    assert n &gt;= 0

    if n == 0:
        return []

    if n == 1:
        return [[['/', 1], ['\\', 2]],                       #  /\
                [['/', 0], ['_', 1], ['_', 2], ['\\', 3]]]   # /__\

    # ok, a bit more complicated:
    # let's assemble top part and the bottom parts seperately
    # check out the N=4 example above
    # there are 3 big triangles: the top one sits on the "spikes"
    # of the bottom two.
    # but those 3 triangles are made of 3 smaller triangles,
    # where the top of the small triangle sits on the bottom
    # 2, and so on...
    top, bottom = [], []
    for line in get_sierpinski(n-1):
        t, bl, br = [], [], []
        for (character, start) in line:
            t.append([character, start+2**(n-1)])
            bl.append([character, start])       # left triangle
            br.append([character, start+2**n])  # right triangle
        top.append(t)
        bottom.append(bl + br)
    return top + bottom

def print_triangle(triangle):
    for line in triangle:
        current_column = 0
        for (character, start) in line:
            while current_column != start:
                sys.stdout.write(" ")
                current_column += 1
            sys.stdout.write(character)
            current_column += 1
        sys.stdout.write("\n")


if __name__ == "__main__":
    size = 3
    if sys.argv[1:]:
        size = int(sys.argv[1])
    print_triangle(get_sierpinski(size))

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-3129114374263606505?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/3129114374263606505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/3129114374263606505'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/02/sierpinski-in-ascii-in-python.html' title='Sierpinski &amp;mdash; in ASCII, in Python'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-4259015877647291249.post-8888862290959255755</id><published>2006-10-07T19:58:00.000-07:00</published><updated>2007-02-11T21:02:51.204-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Google Calendar w/ Python on Nokia 6600</title><content type='html'>I, recently: downloaded Python for my Nokia 6600 and also started using Google Calendar. After seeing Google Calendar's &lt;a href="http://www.google.com/support/calendar/bin/answer.py?answer=37228&amp;amp;topic=8568"&gt;SMS interface&lt;/a&gt; I made it a little easier to use from my cell:
(this works under nokia 6600 and python for s60 2nd edition, 1.3.1)

&lt;pre&gt;
# under mit license
# Oct 6, 2006; sri
import appuifw, time, messaging

gcal_sms_addr = "48368"
monthnames = [u"Jan", u"Feb", u"Mar", u"Apr", u"May", u"Jun",
              u"Jul", u"Aug", u"Sep", u"Oct", u"Nov", u"Dec"]

def gsend(x):
    x = unicode(x)
    messaging.sms_send(gcal_sms_addr, x)
    print "Message sent\n", x

# spits out messages like
# "nov 2 2108 12:00pm try out ruby" to gcal
def create_new():
    now = time.time()
    year, month, day, hour, min = time.localtime(now)[:5]

    date = appuifw.query(u"Date:", "date", now)
    if date is None:
        return
    ttime = appuifw.query(u"Time:", "time", float(3600*hour+60*min))
    if ttime is None:
        return
    event = appuifw.query(u"Event:", "text")
    if not event:
        return

    year2, month2, day2 = time.localtime(date)[:3]
    hour2, sec2 = divmod(int(ttime), 3600)
    min2, _ = divmod(sec2, 60)

    if hour2 &gt;= 12:
        ampm = "pm"
    else:
        ampm = "am"

    gevent = "%s %d %d %d:%02d%s %s" % (
        monthnames[month2-1],
        day2,
        year2,
        hour2,
        min2,
        ampm,
        event)
    gsend(gevent)

def next_event():
    gsend("next")
def todays_events():
    gsend("day")
def tommorows_events():
    gsend("nday")

def main():
    # Currently available Google calendar
    # actions via SMS
    menuitems = [(u"Create new", create_new),
                 (u"Next", next_event),
                 (u"Today's", todays_events),
                 (u"Tommorow's", tommorows_events)]
    
    sel = appuifw.popup_menu([x[0] for x in menuitems],
                             u"GCal actions")
    if sel is None:
        return
    menuitems[sel][1]()

if __name__ == "__main__":
    main()


&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4259015877647291249-8888862290959255755?l=defcraft.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8888862290959255755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4259015877647291249/posts/default/8888862290959255755'/><link rel='alternate' type='text/html' href='http://defcraft.blogspot.com/2007/02/google-calendar-w-python-on-nokia-6600.html' title='Google Calendar w/ Python on Nokia 6600'/><author><name>sri</name><uri>http://www.blogger.com/profile/08283149144110943486</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>
