<?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-4668281529795694673</id><updated>2012-02-01T09:31:26.188-08:00</updated><category term='script'/><category term='wxpython'/><category term='python'/><category term='disk usage'/><category term='function'/><category term='class'/><title type='text'>Strain the Brain - A Technical Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-3053355971113755030</id><published>2009-04-27T07:21:00.000-07:00</published><updated>2009-04-27T07:48:57.092-07:00</updated><title type='text'>Building your own Digital TV Antenna - Why pay for cable?</title><content type='html'>Some of my readers may have seen stuff like this before, but there's plenty who haven't.  I came across a video about a month back over at &lt;a href="http://makezine.tv/episodes/#104"&gt;makezine.tv&lt;/a&gt; that showed how to build this crazy looking tv antenna.  Me being the dissatisfied owner of an overpriced store-bought version, I decided to embark on the journey of duplicating this miraculous antenna to see if it held up to the hype.
&lt;br&gt;&lt;br&gt;
After watching the video I then turned to the PDF plans that they provided that correspond to the video which can be &lt;a href="http://cachefly.oreilly.com/make/television/04/DTV_Antenna_FINAL.pdf"&gt;found here&lt;/a&gt;.
&lt;br&gt;&lt;br&gt;
My original antenna looked like the following, a sleek flat ribbon-like antenna that had dreams of proving itself to its owner, only to fall short.
&lt;br&gt;&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_t4K3NwHabzM/SfXBSMo7IrI/AAAAAAAAAOo/lbnFqb76TeA/s1600-h/IMG_1336.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 175px;" src="http://3.bp.blogspot.com/_t4K3NwHabzM/SfXBSMo7IrI/AAAAAAAAAOo/lbnFqb76TeA/s400/IMG_1336.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5329378252437529266" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
With the above antenna, after a fresh programming of my HDTV set, I could pick up 12 digital stations and 9 analog stations.  The mere fact that I could "pick them up" does not mean that they were stable and watchable all the time.  More often than not, many of the digital stations would constantly go from beautiful perfect quality to flat out darkness (one of the nice attributes of the digital era).  This proved to be quite annoying and would eventually force me back toward its analog counterpart.  Obviously in the near future (if they stop changing the freakin' date!) this will no longer be an option so I figured it was time to do something about this reception issue.
&lt;br&gt;&lt;br&gt;
Now here's a couple shots of my finished product for the new antenna.  
&lt;br&gt;&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_t4K3NwHabzM/SfXCaJU39ZI/AAAAAAAAAO4/dIyZzm4RLQ8/s1600-h/IMG_1334.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="http://3.bp.blogspot.com/_t4K3NwHabzM/SfXCaJU39ZI/AAAAAAAAAO4/dIyZzm4RLQ8/s400/IMG_1334.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5329379488498709906" /&gt;&lt;/a&gt;
&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_t4K3NwHabzM/SfXCTWxKK1I/AAAAAAAAAOw/UjfKv5MJqyE/s1600-h/IMG_1335.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="http://3.bp.blogspot.com/_t4K3NwHabzM/SfXCTWxKK1I/AAAAAAAAAOw/UjfKv5MJqyE/s400/IMG_1335.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5329379371847920466" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
I didn't stray too far from the original PDF plans, although some minor liberties were taken, based on parts availability at the local hardware stores.  I actually ended up buying a spool of 16 guage fencing wire from Lowes since all of our coat hangers in the house are made out of plastic.  The spool was pretty cheap (&lt; $5 for about 100ft. of it I think) so I figured it was worth picking it up rather than hanger hunting!  The only other part where I marginally strayed was with some of the screw sizes / washer sizes, and of course, the plywood base which is more or less left up to the do-it-yourselfer.
&lt;br&gt;&lt;br&gt;
Anyhow, onto the results.  With the new antenna I merrily went about my way, pushing that magical reprogram button again on the tv, after confirming that the antenna was facing the optimal direction for my house (this can be done by visiting &lt;a href="http://www.antennaweb.org/aw/Welcome.aspx"&gt;this site&lt;/a&gt; and typing in your address - they offer a map that will show you where to point the antenna from your exact house!).  The results were amazing, with 24 digital stations and 12 analog stations, all picked up for free over the air.  The 24 digital stations are very stable and rarely ever flicker off.  I didn't care so much about the analog versions anymore and have saved off my favorites as to avoid them since they look horrible to begin with and will be phased out soon enough.
&lt;br&gt;&lt;br&gt;
It's worth noting that folks who subscribe to cable television do not actually receive true HDTV quality television, as your cable provider actually compresses the quality of the broadcast through their lines as it makes its way to your house.  Catching over-the-air broadcast actually catches the full HD quality.  Kind of ironic that most people pay money for lesser quality.  Now obviously if you want to watch stations that aren't available via antenna, well I can't help you there.
&lt;br&gt;&lt;br&gt;
I hope you have all enjoyed the article and are inspired to make one of these antennas on your own, as it doesn't take too much cash nor time to get it up and running.  Best of luck!  Please let me know in the comments how your creations go.
&lt;br&gt;&lt;br&gt;
Cheers,&lt;br&gt;
Chris&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-3053355971113755030?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/3053355971113755030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=3053355971113755030' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/3053355971113755030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/3053355971113755030'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2009/04/building-your-own-digital-tv-antenna.html' title='Building your own Digital TV Antenna - Why pay for cable?'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_t4K3NwHabzM/SfXBSMo7IrI/AAAAAAAAAOo/lbnFqb76TeA/s72-c/IMG_1336.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-8224559914344339142</id><published>2009-01-29T08:43:00.000-08:00</published><updated>2009-01-29T08:55:19.056-08:00</updated><title type='text'>GPG (PGP) Public/Private Key Encryption/Decryption/Signing using the Command Line</title><content type='html'>I've had a couple emails asking about public/private key security and how you can perform this task without the need for GUI-based applications.  Below you will see an example command line session of mine showing the complete process from plain text to cipher and back to plain text.

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Macintosh:Desktop chris$ cat test.txt
This is a test secret message.
Macintosh:Desktop chris$ gpg -sea -r 'Christopher M. Ball' test.txt 

You need a passphrase to unlock the secret key for
user: &amp;quot;Christopher M. Ball &amp;lt;chris.m.ball@gmail.com&amp;gt;&amp;quot;
1024-bit DSA key, ID 0B9FD4CE, created 2007-11-01

Macintosh:Desktop chris$ cat test.txt.asc 
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.8 (Darwin)

hQIOA5PL0Y5P2m2zEAf/b+o5ISTGorJnloGYyAnmt4hw17r98MZ57IFOB/AAJ4hG
Sp/Ru72+0qhEW/IbsX+i4bLO7bAyoPY47yw549yALP621O6s+mqrisrC0nJ33N8v
smyJ8sROn+Pzf53Xkf41wmTgssgSZAd3B60wrmf+AW0csHfjWAd6n8h9lw53HwfR
uzvG3CIkElo6eTG447qGXW07e7AbjlFRAOuuzn9YgvDLHHbpYM38o/snufOOkejD
lyeUQTVwOOxNa4nAQJYSO6Xwd9YP7+MsntbR598DsA5xLRlXxZsEplkoE3c0hRDh
3PCcIeBDUaXC7ZLDc/on7CrL5S7NJUEKGeAx7GMgOgf/QClLSBkMYrO31wbGd4ga
27YLUJNNdGRXIGHsJy/03OGYPh1tKS7xXYJd6q2oK1t9qlyWKTmBLLndIa3UvslF
MVsz7tLqKwr873lBWwdpNBS9YQiBNjqVwNyh4S3XVzzb8RsAa9WSRO2WGqOGaktf
VsfwDdVFmrNwu57f24U2TYzAUWaij/W/e3ANwor6FpvNva8AT9yO0d5xz+PYRXrw
n9UkPQR12TAZ94bcDWq0VWp/yJp+9zMT0MY/kilq4eQxaX6Ha3MtRz+GX7OizK9a
VdSly/AC4RHFVqbK1qhhq8U2Uu7ce0DUs9NYc0DxcoGzz28KFv2RGekh1Pbo+Lx/
j9KxAeL0+F+sdeojxktqmtG1Lp+z1TKrQ69VhQlSOT+kjMH/UfUqjMmCsA9v8t7Q
xRA+AK00K6FWV/x8AcG5ypTeq3DeWLrHLfdB6Ct8iA3yUF8qIGH60jRyXpY/jIL+
pJ7mxNcBQS33RNuoI2eOok5+aAZZERM1DRJKEzJN+PQf8YKG/ZesCRzGO1Di6sgB
J3o/JKnvrGyuXDZ8cmLHvajXk8hKAvQdvKmRl5rMnLiuP2/B
=i0iO
-----END PGP MESSAGE-----
Macintosh:Desktop chris$ rm test.txt
Macintosh:Desktop chris$ gpg test.txt.asc 

You need a passphrase to unlock the secret key for
user: &amp;quot;Christopher M. Ball &amp;lt;chris.m.ball@gmail.com&amp;gt;&amp;quot;
2048-bit ELG-E key, ID 4FDA6DB3, created 2007-11-01 (main key ID 0B9FD4CE)

gpg: encrypted with 2048-bit ELG-E key, ID 4FDA6DB3, created 2007-11-01
      &amp;quot;Christopher M. Ball &amp;lt;chris.m.ball@gmail.com&amp;gt;&amp;quot;
gpg: Signature made Thu Jan 29 08:41:07 2009 PST using DSA key ID 0B9FD4CE
gpg: Good signature from &amp;quot;Christopher M. Ball &amp;lt;chris.m.ball@gmail.com&amp;gt;&amp;quot;
Macintosh:Desktop chris$ cat test.txt
This is a test secret message.

&lt;/code&gt;&lt;/pre&gt;

We typically do not send messages to ourselves, but this example shows the basic practice.  In a future posting I will put together a similar simple example of how to generate your private/public key pairs using the command line, so stay tuned.
&lt;br&gt;&lt;br&gt;
Cheers,&lt;br&gt;
Chris&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-8224559914344339142?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/8224559914344339142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=8224559914344339142' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8224559914344339142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8224559914344339142'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2009/01/gpg-pgp-publicprivate-key.html' title='GPG (PGP) Public/Private Key Encryption/Decryption/Signing using the Command Line'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-6181603683992827326</id><published>2009-01-26T08:00:00.000-08:00</published><updated>2009-01-26T08:31:55.166-08:00</updated><title type='text'>Internet Security 101: Monster.com data stolen (again?)</title><content type='html'>Time and time again I see businesses reporting that their sensitive data has been stolen or hacked into.  &lt;a href="http://www.pcworld.com/businesscenter/article/158270/monstercom_reports_theft_of_user_data.html"&gt;This&lt;/a&gt; latest report from PCWorld suggests that Monster.com still has yet to learn some of the basics of security, as this is the second time I recall seeing an article of this nature on Monster.
&lt;br&gt;&lt;br&gt;
While it doesn't make sense to hash ALL of the data for a customer, some pieces of data can often times be stored in a completely hashed format or at least partially hashed format.  Some examples might include your &lt;i&gt;password&lt;/i&gt; or &lt;i&gt;social security number&lt;/i&gt;.
&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;What is a hash you ask?&lt;/span&gt;&lt;br&gt;A hash is nothing more than an algorithm that accepts an input (usually in the form of a file or string) and provides an output result in the form of a series of numbers and letters.  One of the more popular hashing algorithms available is called MD5.
&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;How does one &lt;i&gt;hash&lt;/i&gt; a password?&lt;/span&gt;&lt;br&gt;Depending on whether you're doing hashing within a piece of software or just manually at home, you might make use of the encryption libraries from Microsoft's Enterprise Libraries, or you might just open up the terminal (for you Mac users out there) and type the following:

&lt;blockquote&gt;Macintosh:~ chris$ md5 -s "MyPassword"&lt;br&gt;
MD5 ("MyPassword") = 48503dfd58720bd5ff35c102065a52d7&lt;/blockquote&gt;

&lt;span style="font-weight:bold;"&gt;Can't a thief simply figure out the password from the hash?&lt;/span&gt;&lt;br&gt; Nope!  That's the beauty of hashes.  Think of them as one way trains.  Once you get on the train and reach your destination.  There's no way to return home.  Now if you somehow manage to make your way back to your point of origination, you can certainly hop on the same train and you'll reach the exact same destination again guaranteed.  This is the basis for how authentication works for your average commercial website.
&lt;br&gt;&lt;br&gt;
During the enrollment / registration period when you usually pick your username and password, if the website was properly designed and security was not ignored, the moment you push "register", the site will check to make sure the username doesn't already exist.  Once this pass is confirmed, your plain text password will be passed off to something like an MD5 hash function which will then spit out the resulting hash.  It is this resulting hash that is then stored in the database table alongside your username.  Each and every &lt;i&gt;future&lt;/i&gt; time you log in again, your password gets passed through the same hashing function and is then compared to the hash stored in the database.  Assuming the hashes match, voila, you're allowed to enter!
&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;How is it then that I can tell a site that I forgot my password and they will email it to me?&lt;/span&gt;&lt;br&gt;That is your first sign that the site you are signed up with stores passwords insecurely.  If the password is hashed, the company storing your data can't figure out your password.  This is where the password reset page comes into play, often accompanied by multi factor authentication (MFA) questions, such as "What was the name of your first pet dog?".
&lt;br&gt;&lt;br&gt;
It boggles the mind that so many large corporations have failed and still continue to fail implementing some of the most basic features of data security.  Should you ever be in a position to help enforce data security practices, please please please remember to ask whether sensitive data that doesn't need to be retrieved is being stored in its hashed state.
&lt;br&gt;&lt;br&gt;
Cheers,&lt;br&gt;
Chris&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-6181603683992827326?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/6181603683992827326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=6181603683992827326' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6181603683992827326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6181603683992827326'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2009/01/internet-security-101-monstercom-data.html' title='Internet Security 101: Monster.com data stolen (again?)'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-5218799076455778153</id><published>2008-12-30T15:19:00.000-08:00</published><updated>2008-12-30T19:11:50.659-08:00</updated><title type='text'>C++ and SDL Video Game Creation: Breakout a.k.a. Arkanoid</title><content type='html'>Over the last several weeks, I've been focusing on a passion I've had ever since I first laid my hands on the Atari and Nintendo consoles back in the 80s; video game development.&lt;br&gt;&lt;br&gt;
I remember having a blast playing the game Breakout but wasn't sure whether I could muster up the skills necessary to develop it straight out the gate since my professional forte is C#.NET development for business applications rather than game development using C++.
&lt;br&gt;&lt;br&gt;
Based on some of the more popular game development sites out there, the general recommendation was to start with very basic games first, such as Tic-Tac-Toe, Blackjack or Connect Four.  Get use to these types of event-driven games that take advantage of the basic game loop structure without the necessity for motion, collision detection, sound, state machines, you name it.
&lt;br&gt;&lt;br&gt;
So I took to the adventure of creating a GUI-based Tic-Tac-Toe with intelligent AI that holds its own fairly well.  This rather mundane game was actually a very valuable experience and pushed me toward my original intent: Breakout.  Let me start by saying, &lt;b&gt;do not skip the easy games&lt;/b&gt; if you're thinking about going down the road of game development.  It is completely unbelievable how much you learn if you truly take the time to do things right with an object-oriented approach in mind.
&lt;br&gt;&lt;br&gt;
While this game is still in development, I've put in a lot of hours on it over the holidays and it is coming together amazingly well.  There's still a ton of stuff I want to do with this one, but I've integrated numerous concepts into the game thus far, including physics motion, collision detection, sprite animation, sound effects, time-based frames per second (FPS) cap control, hotkeys, in-game screenshots, event handling, etc...There's a few bugs I'm still working out as I go, but all in all, a very smooth and responsive game so far!
&lt;br&gt;&lt;br&gt;
I still have numerous "weapons" left to design and integrate into the playing field, along with a fully functional state machine so that I can present menu systems prior to the game starting, but I wanted to share what I had, as I'm very pleased with the results.
&lt;br&gt;&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_t4K3NwHabzM/SVqzOL_hZYI/AAAAAAAAALg/AFtcft3NDZc/s1600-h/screenshot1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 250px;" src="http://2.bp.blogspot.com/_t4K3NwHabzM/SVqzOL_hZYI/AAAAAAAAALg/AFtcft3NDZc/s400/screenshot1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5285734168991458690" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_t4K3NwHabzM/SVqzTDrDyOI/AAAAAAAAALo/jSPboQHhX48/s1600-h/screenshot2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 250px;" src="http://4.bp.blogspot.com/_t4K3NwHabzM/SVqzTDrDyOI/AAAAAAAAALo/jSPboQHhX48/s400/screenshot2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5285734252657494242" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_t4K3NwHabzM/SVqzYPBqXpI/AAAAAAAAALw/MxJZ0e7o7ek/s1600-h/screenshot3.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 250px;" src="http://3.bp.blogspot.com/_t4K3NwHabzM/SVqzYPBqXpI/AAAAAAAAALw/MxJZ0e7o7ek/s400/screenshot3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5285734341604433554" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
You'll notice in the above screenshots that there is a funny little cluster of red balls.  They are actually animated as they fall.  That is my "multi-ball" weapon.  If you manage to catch it with the paddle before it falls into oblivion, you get a nice spray of 6 balls that shoot out of the paddle.  I currently have only this weapon but more will be coming soon.  As of now, the weapon is assigned randomly to approximately 5% of the bricks for a given level.  I'm still playing with figures.
&lt;br&gt;&lt;br&gt;
Speaking of levels, another one of the most impressive features of the game is the light-weight level editor concept.  You can create your own levels with a simple array of numbers in notepad.  It currently supports 5 different colored bricks, each of which has a different internal strength (i.e. number of hits that it can sustain before going &lt;i&gt;poof&lt;/i&gt;).
&lt;br&gt;&lt;br&gt;
Since I'm sure some of my readers will ask that I provide more specifics on the development tools I use at home, here's the list: Mac OS X Leopard 10.5.5, XCode 3.1.2, SVN 1.4.4, C++, SDL 1.2.  The cool thing is that C++ &amp; SDL are cross-platform so there's not too much effort involved in creating a Windows or Linux port of my games down the road.
&lt;br&gt;&lt;br&gt;
For those of you out there thinking about developing some of your own games, feel free to leave a comment if you have any basic questions that I might be able to help with.
&lt;br&gt;&lt;br&gt;
Cheers,&lt;br&gt;
Chris&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-5218799076455778153?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/5218799076455778153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=5218799076455778153' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/5218799076455778153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/5218799076455778153'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/12/c-and-sdl-video-game-creation-breakout.html' title='C++ and SDL Video Game Creation: Breakout a.k.a. Arkanoid'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_t4K3NwHabzM/SVqzOL_hZYI/AAAAAAAAALg/AFtcft3NDZc/s72-c/screenshot1.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-2922755120327781306</id><published>2008-12-29T09:10:00.000-08:00</published><updated>2008-12-29T09:19:41.891-08:00</updated><title type='text'>Setting up XCode 3.1.2 to work with Subversion 1.4.4</title><content type='html'>I've been doing a lot of development in XCode lately and had to brute force my way through the learning process of how to start running my own Subversion repository at home.  It seems so easy at work...you just point Tortoise to this magical repository that already exists and voila, source control!  At home it can be a bit more tricky.  Fear not.  I took copious notes on the process and have decided to be kind and save others from similar grief.  Plus, this post will also serve as a nice memory jogger for me if I ever have to set this all up again.
&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Step 1&lt;/span&gt;
&lt;br&gt;&lt;br&gt;
Open up Terminal.app and type "svnadmin create /Users/chris/SVN" at the prompt.
&lt;br&gt;&lt;br&gt;
Needless to say, choose your own directory of course, in the likely event you don't share my name.  If you were to navigate to this directory after executing the command above, you'll notice that svnadmin has essentially setup an entire folder structure that SVN will use to maintain your repositories.
&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Step 2&lt;/span&gt;
&lt;br&gt;&lt;br&gt;
Head to the following "XCode.app -&gt; SCM -&gt; Configure Repositories"
&lt;br&gt;&lt;br&gt;
Name: Home&lt;br&gt;
URL: file:///Users/chris/SVN&lt;br&gt;
Scheme: file&lt;br&gt;
Host: [blank]&lt;br&gt;
Path: /Users/chris/SVN&lt;br&gt;
Port: [blank]&lt;br&gt;
User: [blank]&lt;br&gt;
Password: [blank]&lt;br&gt;
&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Step 3&lt;/span&gt;
&lt;br&gt;&lt;br&gt;
Using finder, go to the project folder that you want to import into your SVN repository.  Delete the "build" directory if it is within the project folder, as we do not want to keep track of this folder within SVN.  If we fail to do this, we will get all sorts of lovely errors within XCode when we try to do anything with our repository and local code.
&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Step 4&lt;/span&gt;
&lt;br&gt;&lt;br&gt;
Return to your "SCM -&gt; Repositories" window.  Select "import" and select your project folder.  Once this is done, delete the original folder from your finder window and perform a "checkout" from the repository window.  This effectively grabs the code you just imported plus it sets up the .svn hidden folders that SVN needs.
&lt;br&gt;&lt;br&gt;
&lt;span style="font-weight:bold;"&gt;Step 5&lt;/span&gt;
&lt;br&gt;&lt;br&gt;
Open up your project within XCode.  Head to the "SCM -&gt; Configure SCM for this project" menu.
&lt;br&gt;&lt;br&gt;
Project Format: XCode 3.1 compatible&lt;br&gt;
Base SDK: Current Mac OS&lt;br&gt;
SCM Repository: Home (Subversion) - Recommended&lt;br&gt;
&lt;br&gt;
At this point, you should be all set!  Any changes that you make will have an "M" appear next to the file within XCode.  When you've finished making changes to a file, simply go to the "SCM -&gt; Commit entire project" menu and provide a comment. 
&lt;br&gt;&lt;br&gt;
If at any point you want to make a file backup of your project to an external hard drive (if for example you're using your own local machine as I am for your SVN repository), then you can use the "export" feature within the "Xcode.app -&gt; SCM -&gt; Repositories" menu and dump your code to wherever you choose.  You'll notice that the export feature does not include the ".svn" folders which is exactly what you want, just the raw source code with no SVN-related goodies!
&lt;br&gt;&lt;br&gt;
Cheers,&lt;br&gt;
Chris&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-2922755120327781306?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/2922755120327781306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=2922755120327781306' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/2922755120327781306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/2922755120327781306'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/12/setting-up-xcode-312-to-work-with.html' title='Setting up XCode 3.1.2 to work with Subversion 1.4.4'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-8422990959119516396</id><published>2008-03-16T09:42:00.000-07:00</published><updated>2008-03-16T10:23:10.234-07:00</updated><title type='text'>Chess - Could There Be a Better Game?</title><content type='html'>I've been getting back into the wonderful world of chess, ever since a colleague of mine asked that I start bringing in chess to play at lunch.  I broke out the old dusty books I have on chess to sharpen up and started playing a handful of games online.&lt;br&gt;&lt;br&gt;

One thing I completely forgot about was the plethora of free historical games available on the net, ready to be studied.  For those of you who don't know, Portable Game Notation (PGN) is a simple standardized way of notating the moves that occur in a chess match.  What's cool about this is you end up with a unified way of sharing information about the matches across the world, without any language barriers to overcome.  Best of all, if you do some searching, you'll come across literally thousands of world championship matches for free.&lt;br&gt;&lt;br&gt;

I plucked out a game I was studying of Fischer versus Spassky, and my face immediately looked puzzled as the game quickly ended in a small 11 moves.  I found a way to offer an embedded PGN viewer on my blog so have fun with this one.  It's quick but requires utmost attention.&lt;br&gt;&lt;br&gt;

&lt;iframe scrolling = "no" width = "400" frameborder = "0" height = "580" src="http://www.chessvideos.tv/replayer-insert.php?id=3961" style = "border: 1px solid black;"&gt;&lt;/iframe&gt;
&lt;br&gt;&lt;br&gt;
After staring at the final positions for about 30 seconds, it hit me, ohhhhhh!  I kept asking myself, why on earth did black resign?  I swore up and down I finally saw the holy grail of why this game ended, but then, there was a way out!  Here's the final positions of the game, white to move:&lt;br&gt;&lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_t4K3NwHabzM/R91Q0DYpHuI/AAAAAAAAAEY/CJ-Qf5f32is/s1600-h/screenshot+(2008.02.16-09.33.10).png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_t4K3NwHabzM/R91Q0DYpHuI/AAAAAAAAAEY/CJ-Qf5f32is/s400/screenshot+(2008.02.16-09.33.10).png" border="0" alt=""id="BLOGGER_PHOTO_ID_5178384001738022626" /&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;

Here's what I thought caused the game to end, and quite possibly it did, but maybe this was an overlooked "out"?&lt;br&gt;&lt;br&gt;

12. Nc6! Qc8&lt;br&gt;
13. Nxe7!+&lt;br&gt;&lt;br&gt;

At this point, we've got a king in check with a forked queen, so I thought that would be a reason to call it quits, but what about:&lt;br&gt;&lt;br&gt;

13. ... Rxe7!&lt;br&gt;&lt;br&gt;

That would have removed the entire threat.  Given the fact that these guys were rated 2785 (Fischer) and 2660 (Spassky) in this match, I doubt I'll ever fully understand why it ended.&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/03/chess-could-there-be-better-game.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-8422990959119516396?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/8422990959119516396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=8422990959119516396' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8422990959119516396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8422990959119516396'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/03/chess-could-there-be-better-game.html' title='Chess - Could There Be a Better Game?'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_t4K3NwHabzM/R91Q0DYpHuI/AAAAAAAAAEY/CJ-Qf5f32is/s72-c/screenshot+(2008.02.16-09.33.10).png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-7868145149437948426</id><published>2008-03-02T08:44:00.000-08:00</published><updated>2008-03-02T09:18:05.300-08:00</updated><title type='text'>HD Format Wars Over? Playstation 3 Here I Come.</title><content type='html'>While I doubt I'm the only person out there who's been eager for the digital format wars to end, the recent events were honestly a blessing in hammering those last couple nails into the coffin:

&lt;ul&gt;&lt;li&gt;Toshiba &lt;a href="http://www.engadget.com/2008/02/19/live-from-toshibas-hd-dvd-press-conference-in-tokyo/"&gt;drops&lt;/a&gt; the manufacturing of all HD-DVD players.&lt;/li&gt;&lt;li&gt;Netflix and Wal-Mart &lt;a href="http://www.cbsnews.com/stories/2008/02/28/scitech/pcanswer/main3890714.shtml"&gt;drop&lt;/a&gt; all HD-DVD support.&lt;/li&gt;&lt;li&gt;Microsoft &lt;a href="http://techreport.com/discussions.x/14219"&gt;drops&lt;/a&gt; the HD-DVD add-on package for the Xbox 360.&lt;/li&gt;&lt;/ul&gt; 

My reasons for thinking the coffin was a good thing for us all?

&lt;ul&gt;&lt;li&gt;There's the technical reasons of course, Blu-ray discs do technically hold a lot more data on them.  This enables content creators to go a bit more hog-wild with content creation for us, both in movies as well as in video games (more cut-scenes!).&lt;/li&gt;&lt;li&gt;There's also the pricing model of the Playstation 3.  From some basic hunting and pecking around on the net, your average Blu-ray player costs you around $350.  For an extra $50, you've got a really good Blu-ray player and you've also got a really sweet gaming platform that Sony is apparently investing upwards of 10 years into.&lt;/li&gt;&lt;li&gt;Another sweet aspect here is because the PS3 is completely wifi-enabled, you can always keep your player up to date with the latest firmware updates from Sony, while a standard player wouldn't likely have a reason to have wifi on it in the first place.&lt;/li&gt;&lt;li&gt;We won't have to own both players or wait for the creation of dual-format players. Enough said.&lt;/li&gt;&lt;/ul&gt;

Needless to say, I took the plunge this weekend and picked up a PS3 and a couple games to boot, very impressed with the system as well as my game choices thus far. Definitely looking forward to seeing an increase in quantity of Blu-ray content on Netflix.&lt;br&gt;&lt;br&gt;

Disclaimer:  By no means is this post geared toward proclaiming one particular gaming console better than the other.  I believe each have their strengths and weaknesses.  It all boils down to the individual and the game selections available.  While I personally don't have an interest in owning an Xbox 360, I would also eventually like to pick up the Nintendo Wii, but given the lack of stock in the US, that might not be until next Christmas :).&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/03/hd-format-wars-over-playstation-3-here.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-7868145149437948426?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/7868145149437948426/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=7868145149437948426' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/7868145149437948426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/7868145149437948426'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/03/hd-format-wars-over-playstation-3-here.html' title='HD Format Wars Over? Playstation 3 Here I Come.'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-8933613919469646420</id><published>2008-02-24T19:09:00.000-08:00</published><updated>2009-01-06T07:57:25.019-08:00</updated><title type='text'>Building a Cocoa Calculator Application with XCode 3 for Mac (Part 3)</title><content type='html'>The long awaited part 3 of my Cocoa Calculator series is complete and has arrived in high style, or should I say resolution?  This is by far the longest in the series, coming in at a whopping 25 minutes.  I am also providing the full source code so that you guys don't have to feverishly copy code from the video but can refer to it afterwards for reference if you need help building out your very own!
&lt;br&gt;&lt;br&gt;
&lt;b&gt;Edit (1/6/09)&lt;/b&gt;: Thanks to one of my readers, we now have a secondary mirror site for downloading the video.  Download locations: &lt;a href="http://www.sendspace.com/file/2ch53n"&gt;Mirror 1&lt;/a&gt; &lt;a href="http://bsdeviant.org/mirror/CalcPart3.mp4"&gt;Mirror 2&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;//
//  CalcModel.h
//  SimpleCalc
//
//  Created by Chris Ball (chris.m.ball@gmail.com) on 1/17/08.
//  Copyright 2008, Chris Ball, Strainthebrain.Blogspot.Com. 
//  All rights reserved.
//

#import &amp;lt;Cocoa/Cocoa.h&amp;gt;

@interface CalcModel : NSObject {
    float running_total;
    char  sign_state;
    bool  first_call;
}

//Establishing some public-facing properties.
@property(readwrite) float running_total;
@property(readwrite) char  sign_state;
@property(readwrite) bool  first_call;

//Used for computing and maintaing the model data.
- (void) computeNewDisplayVal: (float) currDisplayVal;

@end
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;br&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;//
//  CalcModel.m
//  SimpleCalc
//
//  Created by Chris Ball (chris.m.ball@gmail.com) on 1/17/08.
//  Copyright 2008, Chris Ball, Strainthebrain.Blogspot.Com. 
//  All rights reserved.
//

#import &amp;quot;CalcModel.h&amp;quot;

@implementation CalcModel

//Implicity declaring the setters/getters for our properties.
@synthesize running_total, sign_state, first_call;

- (void) computeNewDisplayVal: (float) currDisplayVal {
    if (self.first_call) {
        self.running_total = currDisplayVal;
        self.first_call = NO;
    }
    else {
        switch (self.sign_state) {
            case 'a':
                self.running_total = self.running_total + currDisplayVal;
                break;
            case 'd':
                self.running_total = self.running_total / currDisplayVal;
                break;
            case 'm':
                self.running_total = self.running_total * currDisplayVal;
                break;
            case 's':
                self.running_total = self.running_total - currDisplayVal;
                break;
        }
    }
}

@end
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;br&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;//
//  CalcController.h
//  SimpleCalc
//
//  Created by Chris Ball (chris.m.ball@gmail.com) on 1/17/08.
//  Copyright 2008, Chris Ball, Strainthebrain.Blogspot.Com. 
//  All rights reserved.
//

#import &amp;lt;Cocoa/Cocoa.h&amp;gt;
#import &amp;quot;CalcModel.h&amp;quot;

@interface CalcController : NSObject {
    IBOutlet id calc_display;
    IBOutlet id a_button;
    IBOutlet id s_button;
    IBOutlet id m_button;
    IBOutlet id d_button;
    CalcModel*    calc_model;
}

//Mathematical button events.
- (IBAction) push_add:        (id) sender;
- (IBAction) push_divide:    (id) sender;
- (IBAction) push_multiply:    (id) sender;
- (IBAction) push_subtract:    (id) sender;

//Numeric button events.
- (IBAction) push_zero:        (id) sender;
- (IBAction) push_one:        (id) sender;
- (IBAction) push_two:        (id) sender;
- (IBAction) push_three:    (id) sender;
- (IBAction) push_four:        (id) sender;
- (IBAction) push_five:        (id) sender;
- (IBAction) push_six:        (id) sender;
- (IBAction) push_seven:    (id) sender;
- (IBAction) push_eight:    (id) sender;
- (IBAction) push_nine:        (id) sender;

//Internal functions.
- (void)     push_number:    (id) sender;
- (BOOL)     sign_pushed;
- (void)     check_calc_model;

//Other button events.
- (IBAction) push_clear:    (id) sender;
- (IBAction) push_decimal:    (id) sender;
- (IBAction) push_equal:    (id) sender;

@end
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;br&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;//
//  CalcController.m
//  SimpleCalc
//
//  Created by Chris Ball (chris.m.ball@gmail.com) on 1/17/08.
//  Copyright 2008, Chris Ball, Strainthebrain.Blogspot.Com. 
//  All rights reserved.
//

#import &amp;quot;CalcController.h&amp;quot;
#import &amp;lt;RegexKit/RegexKit.h&amp;gt;

@implementation CalcController

- (IBAction) push_add:        (id) sender {
    if ([m_button state] == NSOnState &amp;#124;&amp;#124; [s_button state] == NSOnState &amp;#124;&amp;#124; [d_button state] == NSOnState) {
        [a_button setState:NSOffState];
    }
    else {
        [self check_calc_model];
        
        if (!calc_model.first_call)
            [self push_equal:0];
        
        calc_model.sign_state = 'a';
        [calc_model computeNewDisplayVal:[calc_display floatValue]];
        [calc_display setFloatValue:calc_model.running_total];
    }
}
- (IBAction) push_divide:    (id) sender {
    if ([a_button state] == NSOnState &amp;#124;&amp;#124; [s_button state] == NSOnState &amp;#124;&amp;#124; [m_button state] == NSOnState) {
        [d_button setState:NSOffState];
    }
    else {
        [self check_calc_model];
        
        if (!calc_model.first_call)
            [self push_equal:0];

        calc_model.sign_state = 'd';
        [calc_model computeNewDisplayVal:[calc_display floatValue]];
        [calc_display setFloatValue:calc_model.running_total];
    }
}
- (IBAction) push_multiply:    (id) sender {
    if ([a_button state] == NSOnState &amp;#124;&amp;#124; [s_button state] == NSOnState &amp;#124;&amp;#124; [d_button state] == NSOnState)
        [m_button setState:NSOffState];
    else {
        [self check_calc_model];

        if (!calc_model.first_call)
            [self push_equal:0];

        calc_model.sign_state = 'm';
        [calc_model computeNewDisplayVal:[calc_display floatValue]];
        [calc_display setFloatValue:calc_model.running_total];
    }
}
- (IBAction) push_subtract:    (id) sender {
    if ([a_button state] == NSOnState &amp;#124;&amp;#124; [m_button state] == NSOnState &amp;#124;&amp;#124; [d_button state] == NSOnState)
        [s_button setState:NSOffState];
    else {
        [self check_calc_model];

        if (!calc_model.first_call)
            [self push_equal:0];

        calc_model.sign_state = 's';
        [calc_model computeNewDisplayVal:[calc_display floatValue]];
        [calc_display setFloatValue:calc_model.running_total];
    }
}

- (IBAction) push_zero:        (id) sender {
    [self push_number:sender];
}
- (IBAction) push_one:        (id) sender {
    [self push_number:sender];
}
- (IBAction) push_two:        (id) sender {
    [self push_number:sender];
}
- (IBAction) push_three:    (id) sender {
    [self push_number:sender];
}
- (IBAction) push_four:        (id) sender {
    [self push_number:sender];
}
- (IBAction) push_five:        (id) sender {
    [self push_number:sender];
}
- (IBAction) push_six:        (id) sender {
    [self push_number:sender];
}
- (IBAction) push_seven:    (id) sender {
    [self push_number:sender];
}
- (IBAction) push_eight:    (id) sender {
    [self push_number:sender];
}
- (IBAction) push_nine:        (id) sender {
    [self push_number:sender];
}

- (void)     push_number:    (id) sender {
    if ([self sign_pushed]) {
        [a_button setState:0];
        [d_button setState:0];
        [m_button setState:0];
        [s_button setState:0];
        [calc_display setStringValue:@&amp;quot;&amp;quot;];
    }
    
    if ([[calc_display stringValue] compare:@&amp;quot;0&amp;quot;] &amp;amp;&amp;amp; !calc_model.first_call)
        [calc_display setStringValue:[[calc_display stringValue] stringByAppendingString:[sender title]]];
    else 
        [calc_display setStringValue:[sender title]];
}
- (BOOL)     sign_pushed {
    if ([a_button state] == NSOnState &amp;#124;&amp;#124; [s_button state] == NSOnState &amp;#124;&amp;#124; [m_button state] == NSOnState &amp;#124;&amp;#124; [d_button state] == NSOnState)
        return YES;
    else return NO;
}
- (void)     check_calc_model {
    @try {
        if (calc_model == nil) {
            calc_model = [[CalcModel alloc] init];
            calc_model.first_call = YES;
        }
    }
    @catch (NSException *ex) {
        NSLog(@&amp;quot;check_calc_model: Caught %@: %@&amp;quot;, [ex name], [ex reason]);
    }
}

- (IBAction) push_clear:    (id) sender {
    if (calc_model != nil) {
        [calc_model release];
        calc_model = nil;
    }
    
    [calc_display setIntValue:0];
    
    if ([self sign_pushed]) {
        [a_button setState:0];
        [d_button setState:0];
        [m_button setState:0];
        [s_button setState:0];
    }
}
- (IBAction) push_decimal:    (id) sender {
    if ([self sign_pushed]) {
        [a_button setState:0];
        [d_button setState:0];
        [m_button setState:0];
        [s_button setState:0];
        [calc_display setStringValue:@&amp;quot;&amp;quot;];
    }
    
    if (![[calc_display stringValue] isMatchedByRegex:@&amp;quot;[.]&amp;quot;])
        [calc_display setStringValue:[[calc_display stringValue] stringByAppendingString:@&amp;quot;.&amp;quot;]];
}
- (IBAction) push_equal:    (id) sender {
    [self check_calc_model];
    [calc_model computeNewDisplayVal:[calc_display floatValue]];
    [calc_display setFloatValue:calc_model.running_total];
    calc_model.first_call = YES;
}

@end
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;br&gt;
&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/02/building-cocoa-calculator-application_24.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;script type="text/javascript"&gt;var dzone_url = 'http://strainthebrain.blogspot.com/2008/02/building-cocoa-calculator-application_24.html';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_title = 'Building a Cocoa Calculator Application with XCode 3 for Mac (Part 3)';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_blurb = 'The long awaited part 3 of my Cocoa Calculator series is complete and has arrived in high style, or should I say resolution? This is by far the longest in the series, coming in at a whopping 25 minutes. I am also providing the full source code so that you guys don't have to feverishly copy code from the video but can refer to it afterwards for reference if you need help building out your very own! ';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-8933613919469646420?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/8933613919469646420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=8933613919469646420' title='54 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8933613919469646420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8933613919469646420'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/02/building-cocoa-calculator-application_24.html' title='Building a Cocoa Calculator Application with XCode 3 for Mac (Part 3)'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>54</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-5492425883084918390</id><published>2008-02-09T21:58:00.000-08:00</published><updated>2008-02-09T22:25:47.749-08:00</updated><title type='text'>Remote Desktop Protocol (RDP) From Mac OS Leopard to Vista Ultimate</title><content type='html'>I've been facing a dilemma at home.  I am absolutely in love with my Mac and all its glory, but I also find myself needing to do Windows .NET development.  Sure, there's boot camp, but that makes the assumption that I want to get into the game of running multiple operating systems on one physical machine.  I'd prefer to be beat over the head repeatedly, given the choice.&lt;br&gt;&lt;br&gt;

There's also the option of Parallels for running a virtual machine.  While that might sound great, assuming I don't mind paying more money for Parallels, Vista is such a big beast that it would likely be somewhat painful to go down this road, unless of course I'm willing to sit back and pop some popcorn in between application loads.&lt;br&gt;&lt;br&gt;

I then pondered if it would be possibly to RDP from my Mac to my Vista machine (in this case my laptop on the local home network is now the ugly stepchild that doesn't get the attention it deserves...Macs will undoubtedly cause this imbalance, sorry Windows).  To my surprise, I was able to get this smoothly working without issue in a matter of minutes.&lt;br&gt;&lt;br&gt;

1.  Enable RDP on your Vista machine.  While I don't have concrete information, I have heard that the lower end version of Vista such as Vista Home may not support RDP inbound, so make sure your version supports this feature.&lt;br&gt;&lt;br&gt;

2.  Install this lovely free RDP client from Microsoft, custom built for the good old Mac (&lt;a href="http://www.microsoft.com/mac/products/remote-desktop/default.mspx"&gt;http://www.microsoft.com/mac/products/remote-desktop/default.mspx&lt;/a&gt;).&lt;br&gt;&lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_t4K3NwHabzM/R66WmJ6Op5I/AAAAAAAAAEM/z9TLMXJbMEc/s1600-h/Picture+1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_t4K3NwHabzM/R66WmJ6Op5I/AAAAAAAAAEM/z9TLMXJbMEc/s400/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5165231404879882130" /&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;

3.  Load the application once it's installed and head straight for the preferences - I made sure to change it so that it would go "full screen" on the display tab, and I also upped the colors to "millions".&lt;br&gt;&lt;br&gt;

4.  Lastly, key in your LAN ip address (i.e. 192.168.x.x) and your windows credentials and you should be all set!&lt;br&gt;&lt;br&gt;

While this will vary from person to person, I was exceedingly pleased with this arrangement, as my screencasting process allows me to capture all of my Vista interactions, just as I capture my Mac interactions.  I'm also now able to do both Objective-C / Cocoa development on my Mac as well as C# / 3.5 .NET on my PC.  Talk about a streamlined multi-OS setup!&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/02/remote-desktop-protocol-rdp-from-mac-os.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;


&lt;script type="text/javascript"&gt;var dzone_url = 'http://strainthebrain.blogspot.com/2008/02/remote-desktop-protocol-rdp-from-mac-os.html';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_title = 'Remote Desktop Protocol (RDP) From Mac OS Leopard to Vista Ultimate';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_blurb = 'I have been facing a dilemma at home. I am absolutely in love with my Mac and all its glory, but I also find myself needing to do Windows .NET development. Sure, there is boot camp, but that makes the assumption that I want to get into the game of running multiple operating systems on one physical machine. I would prefer to be beat over the head repeatedly, given the choice.';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-5492425883084918390?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/5492425883084918390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=5492425883084918390' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/5492425883084918390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/5492425883084918390'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/02/remote-desktop-protocol-rdp-from-mac-os.html' title='Remote Desktop Protocol (RDP) From Mac OS Leopard to Vista Ultimate'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_t4K3NwHabzM/R66WmJ6Op5I/AAAAAAAAAEM/z9TLMXJbMEc/s72-c/Picture+1.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-858910738802886023</id><published>2008-02-02T11:26:00.000-08:00</published><updated>2008-02-03T10:02:11.660-08:00</updated><title type='text'>Building a Cocoa Calculator Application with XCode 3 for Mac (Part 2)</title><content type='html'>Here it is, part 2 of my "Build a Calculator with XCode" series.  Just as before, the technologies involved in this screencast include: XCode 3, Objective-C, the Cocoa Framework, and Interface Builder 3.  This part covers some new concepts including the creation of controller classes, actions, outlets, and binding actions/outlets to different components of your GUI interface.&lt;br&gt;&lt;br&gt;

Once mastered, the knowledge gained from this part in the series will help viewers easily create their very own applications with event handling fully implemented.&lt;br&gt;&lt;br&gt;

I thoroughly enjoyed putting together this screencast.  I have been getting more and more comfortable with video production lately and decided I wanted to try incorporating some soothing Chopin music in the background.  Please let me know if you find it distracting or tastefully applied!&lt;br&gt;&lt;br&gt;

&lt;object width="640" height="480"&gt;&lt;param name="movie" value="http://www.dailymotion.com/swf/x490qu"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.dailymotion.com/swf/x490qu" type="application/x-shockwave-flash" width="640" height="480" allowFullScreen="true" allowScriptAccess="always"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br&gt;&lt;br&gt;

In the next part in the series, I will be taking you through the actual implementation code necessary to make this calculator come to life.  Until next time...&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/02/building-cocoa-calculator-application.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;script type="text/javascript"&gt;var dzone_url = 'http://strainthebrain.blogspot.com/2008/02/building-cocoa-calculator-application.html';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_title = 'Building a Cocoa Calculator Application with XCode 3 for Mac (Part 2)';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_blurb = 'Here it is, part 2 of my "Build a Calculator with XCode" series. Just as before, the technologies involved in this screencast include: XCode 3, Objective-C, the Cocoa Framework, and Interface Builder 3. This part covers some new concepts including the creation of controller classes, actions, outlets, and binding actions/outlets to different components of your GUI interface.';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-858910738802886023?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/858910738802886023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=858910738802886023' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/858910738802886023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/858910738802886023'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/02/building-cocoa-calculator-application.html' title='Building a Cocoa Calculator Application with XCode 3 for Mac (Part 2)'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-7868839940275536821</id><published>2008-01-26T17:02:00.000-08:00</published><updated>2008-02-03T10:13:16.493-08:00</updated><title type='text'>Building a Cocoa Calculator Application with XCode 3 for Mac (Part 1)</title><content type='html'>As promised, for you avid Mac lovers out there wanting to churn out some software of your own, I present you with my latest screencast showing how to build a calculator very similar to the calculator widget that comes with Mac.  This tutorial incorporates the XCode 3 IDE, the Cocoa Framework, Objective-C (well really not until the next part of the series), and Interface Builder 3 (the primary focus of this first screencast).&lt;br&gt;&lt;br&gt;

With some snazzy editing and practice runs, I've managed to condense this large lump of knowledge down to approximately 3 minutes of guns blazing glory.  Okay, maybe not guns blazing, but you get the point.&lt;br&gt;&lt;br&gt;

&lt;object width="640" height="480"&gt;&lt;param name="movie" value="http://www.dailymotion.com/swf/x46f28"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.dailymotion.com/swf/x46f28" type="application/x-shockwave-flash" width="640" height="480" allowFullScreen="true" allowScriptAccess="always"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br&gt;&lt;br&gt;

The next part in the series will go over the concepts of actions and outlets and how to set those up for this calculator application.  In other words, we'll be setting up event handling to make this lovely interface shine (a.k.a respond).&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/01/building-cocoa-calculator-application.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;script type="text/javascript"&gt;var dzone_url = 'http://strainthebrain.blogspot.com/2008/01/building-cocoa-calculator-application.html';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_title = 'Building a Cocoa Calculator Application with XCode 3 for Mac (Part 1)';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_blurb = 'As promised, for you avid Mac lovers out there wanting to churn out some software of your own, I present you with my latest screencast showing how to build a calculator very similar to the calculator widget that comes with Mac. This tutorial incorporates the XCode 3 IDE, the Cocoa Framework, Objective-C (well really not until the next part of the series), and Interface Builder 3 (the primary focus of this first screencast).';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-7868839940275536821?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/7868839940275536821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=7868839940275536821' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/7868839940275536821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/7868839940275536821'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/01/building-cocoa-calculator-application.html' title='Building a Cocoa Calculator Application with XCode 3 for Mac (Part 1)'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-224495065142360784</id><published>2008-01-19T10:58:00.000-08:00</published><updated>2008-02-03T10:16:36.018-08:00</updated><title type='text'>Encrypting &amp; Decrypting on the Mac - Video Screencast</title><content type='html'>I recently picked up some software for producing screencasts for the Mac.  I was eager to produce a blog post more "hands on" for my visitors, so pardon the amateur first attempt.  As with most things, these will improve with practice!&lt;br&gt;&lt;br&gt;

The following video goes over tools provided by the Gnu Privacy Guard (GPG), namely GPG Drop Thing and GPG File Tool.  These tools enable users to encrypt and decrypt information.  I wanted to put together this little gem because most of the time whenever I run into someone and start talking about encrypted emails being the "wave of the future" due to privacy concerns (or should I say violations?), most people get the "deer in the headlights" look - I usually try to settle their nerves by exclaiming just how simple encryption can be for the end user, but most of the time I get the "suuuuuuuure" vibe :)  On with the show!&lt;br&gt;&lt;br&gt;
&lt;object width="640" height="480"&gt;&lt;param name="movie" value="http://www.dailymotion.com/swf/x44lkl"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.dailymotion.com/swf/x44lkl" type="application/x-shockwave-flash" width="640" height="480" allowFullScreen="true" allowScriptAccess="always"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/01/encrypting-decrypting-on-mac-video.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;script type="text/javascript"&gt;var dzone_url = 'http://strainthebrain.blogspot.com/2008/01/encrypting-decrypting-on-mac-video.html';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_title = 'Encrypting &amp; Decrypting on the Mac - Video Screencast';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_blurb = 'The following video goes over tools provided by the Gnu Privacy Guard (GPG), namely GPG Drop Thing and GPG File Tool. These tools enable users to encrypt and decrypt information.';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-224495065142360784?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/224495065142360784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=224495065142360784' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/224495065142360784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/224495065142360784'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/01/encrypting-decrypting-on-mac-video.html' title='Encrypting &amp; Decrypting on the Mac - Video Screencast'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-6090422745377622951</id><published>2008-01-16T09:19:00.001-08:00</published><updated>2008-02-03T10:21:17.477-08:00</updated><title type='text'>C# Generics Performance Gain Benchmarks</title><content type='html'>Some of my readers may recall an earlier post I made (&lt;a href="http://strainthebrain.blogspot.com/2007/12/c-generics-performance-gain-not-so-fast.html"&gt;http://strainthebrain.blogspot.com/2007/12/c-generics-performance-gain-not-so-fast.html&lt;/a&gt;), talking about the lack of performance I was seeing during some testing with generics.  Thanks to a reader, the mystery was clarified.  When testing out generics, make sure that the data type you're declaring is a &lt;b&gt;value type&lt;/b&gt;, not a &lt;b&gt;reference type&lt;/b&gt;!  If you need clarification on which are which (I can admit I did), refer &lt;a href="http://msdn2.microsoft.com/en-us/library/s1ax56ch.aspx"&gt;here&lt;/a&gt; for value types and &lt;a href="http://msdn2.microsoft.com/en-us/library/490f96s2.aspx"&gt;here&lt;/a&gt; for reference types.&lt;br&gt;&lt;br&gt;

I have put together some revised code, as well as implemented a better mechanism for benchmarking code execution performance using the diagnostics stopwatch.&lt;br&gt;&lt;br&gt;

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace GenericsPerformance
{
    class Program
    {
        static void Main(string[] args)
        {
            int intVal = 0;
            string strVal = &amp;quot;&amp;quot;;

            //Generics Test-------------------------------------------------------
            System.Diagnostics.Stopwatch genericSW = new System.Diagnostics.Stopwatch();

            genericSW.Start();
            Stack&amp;lt;int&amp;gt; genStack = new Stack&amp;lt;int&amp;gt;();
            for (int i = 0; i &amp;lt; 1000000; i++)
                genStack.Push(i);
            for (int i = 0; i &amp;lt; 1000000; i++)
                intVal = genStack.Pop();
            genericSW.Stop();

            Console.WriteLine(&amp;quot;Generics (using int): {0} ms&amp;quot;, genericSW.ElapsedMilliseconds);
            //--------------------------------------------------------------------

            //Non-generics Test---------------------------------------------------
            System.Diagnostics.Stopwatch nongenericSW = new System.Diagnostics.Stopwatch();

            nongenericSW.Start();
            Stack nonGenStack = new Stack();
            for (int i = 0; i &amp;lt; 1000000; i++)
                nonGenStack.Push(i);
            for (int i = 0; i &amp;lt; 1000000; i++)
                intVal = (int)nonGenStack.Pop();
            nongenericSW.Stop();

            Console.WriteLine(&amp;quot;Non-Generics (using int): {0} ms&amp;quot;, nongenericSW.ElapsedMilliseconds);
            //--------------------------------------------------------------------

            //Generics Test-------------------------------------------------------
            System.Diagnostics.Stopwatch genericSW2 = new System.Diagnostics.Stopwatch();

            genericSW2.Start();
            Stack&amp;lt;string&amp;gt; genStack2 = new Stack&amp;lt;string&amp;gt;();
            for (int i = 0; i &amp;lt; 1000000; i++)
                genStack2.Push(i.ToString());
            for (int i = 0; i &amp;lt; 1000000; i++)
                strVal = genStack2.Pop();
            genericSW2.Stop();

            Console.WriteLine(&amp;quot;Generics (using string): {0} ms&amp;quot;, genericSW2.ElapsedMilliseconds);
            //--------------------------------------------------------------------

            //Non-generics Test---------------------------------------------------
            System.Diagnostics.Stopwatch nongenericSW2 = new System.Diagnostics.Stopwatch();

            nongenericSW2.Start();
            Stack nonGenStack2 = new Stack();
            for (int i = 0; i &amp;lt; 1000000; i++)
                nonGenStack2.Push(i.ToString());
            for (int i = 0; i &amp;lt; 1000000; i++)
                strVal = (string)nonGenStack2.Pop();
            nongenericSW2.Stop();

            Console.WriteLine(&amp;quot;Non-Generics (using string): {0} ms&amp;quot;, nongenericSW2.ElapsedMilliseconds);
            //--------------------------------------------------------------------

            Console.ReadLine();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

While the results varied slightly each run, I will show you 3 separate runs of this program.  You'll notice that I first show Generics vs. Non-generics using a value type of int (this SHOULD perform better).  I then show Generics vs. Non-generics using a reference type of string (Microsoft makes no claim on performance gain in this instance).&lt;br&gt;&lt;br&gt;

Run 1 Result:
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Generics (using int): 49 ms
Non-Generics (using int): 212 ms
Generics (using string): 911 ms
Non-Generics (using string): 912 ms
&lt;/code&gt;&lt;/pre&gt;

Run 2 Result:
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Generics (using int): 50 ms
Non-Generics (using int): 230 ms
Generics (using string): 935 ms
Non-Generics (using string): 944 ms
&lt;/code&gt;&lt;/pre&gt;

Run 3 Result:
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Generics (using int): 50 ms
Non-Generics (using int): 212 ms
Generics (using string): 899 ms
Non-Generics (using string): 908 ms
&lt;/code&gt;&lt;/pre&gt;

As can be seen, generics using appropriate value types (such as int) show a dramatically improved performance gain, whereas generics using reference types (such as string) only perform slightly better than their non-generic counterpart.&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/01/c-generics-performance-gain-benchmarks.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;script type="text/javascript"&gt;var dzone_url = 'http://strainthebrain.blogspot.com/2008/01/c-generics-performance-gain-benchmarks.html';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_title = 'C# Generics Performance Gain Benchmarks';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_blurb = 'This blog post reviews performance gains that can be seen from C# generics.  It also points out pitfalls when trying to gauge performance and provides full implementation code for performing similar tests.';&lt;/script&gt;
&lt;script type="text/javascript"&gt;var dzone_style = '1';&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-6090422745377622951?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/6090422745377622951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=6090422745377622951' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6090422745377622951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6090422745377622951'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/01/c-generics-performance-gain-benchmarks.html' title='C# Generics Performance Gain Benchmarks'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-3477236463184319683</id><published>2008-01-12T13:44:00.000-08:00</published><updated>2008-01-12T14:26:15.041-08:00</updated><title type='text'>Objective-C using the Cocoa Framework - Part 1</title><content type='html'>Having picked up an iMac this past Christmas, I've been eager to dive into the opposing world of Mac development.  I spend the majority of my time in the workplace developing using C# with the .NET framework.&lt;br&gt;&lt;br&gt;

I spent some time first poking around the net, looking for the best free integrated development environments (IDE) I could find for the Mac OS X Leopard platform.  Before you say it, yes yes, there's always vi(m), emacs, pico, etc.  While I am a fairly large proponent of vim, I was still curious what else was out there.  I took a look around the XCode IDE and was thoroughly impressed with the apparent plethora of project types that could be crafted, however I soon realized I needed to resort to simpler editors first if I really wanted to "understand" some of the new languages and frameworks before letting an IDE do all the mysterious work for me behind the scenes.  After digging around further I came across Smultron.  Great little light-weight app that suits my needs just perfectly for coding.&lt;br&gt;&lt;br&gt;

For those coming from the .NET arena, wanting to sample the goods on this side of the fence, let me present you with my little analogy that helped me keep things straight.  C# is to .NET as Objective-C is to Cocoa.  We are dealing with languages and frameworks containing lots of useful libraries.&lt;br&gt;&lt;br&gt;

While this example isn't completely original, I have made sufficient enough changes and additions to warrant considering this equally informative to that of other beginner examples of the language and framework.  I make no claims to be an expert with Objective-C nor the Cocoa framework, so there may be more efficient ways to perform certain tasks.&lt;br&gt;&lt;br&gt;

We're going to deal with a simple "Fractions" example from your most basic element of math.  Say we wanted to craft our very own Fraction object.&lt;br&gt;&lt;br&gt;

Fraction.h
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#import &amp;lt;Foundation/NSObject.h&amp;gt;

@interface Fraction: NSObject
{
    int numerator;
    int denominator;
}

-(void) print;
-(void) set_Numerator: (int) n Denominator: (int) d;
-(int) get_Numerator;
-(int) get_Denominator;
@end
&lt;/code&gt;&lt;/pre&gt;
Fraction.m
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#import &amp;lt;stdio.h&amp;gt;
#import &amp;quot;Fraction.h&amp;quot;

@implementation Fraction
// ------------------------------------------------------
-(void) print 
{
    printf(&amp;quot;%i/%i%c&amp;quot;, numerator, denominator, '\n');
}

// ------------------------------------------------------
-(void) set_Numerator: (int) n Denominator: (int) d
{
    numerator = n;
    denominator = d;
}
// ------------------------------------------------------
-(int) get_Denominator 
{
    return denominator;
}
// ------------------------------------------------------
-(int) get_Numerator 
{
    return numerator;
}
// ------------------------------------------------------
@end
&lt;/code&gt;&lt;/pre&gt;
main.m
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#import &amp;lt;stdio.h&amp;gt;
#import &amp;quot;Fraction.h&amp;quot;

int main(int argc, const char *argv[]) 
{
    // Allocate and initialize a Fraction object for use
    Fraction *fraction1 = [[Fraction alloc] init];

    // Call our set_Numerator:Denominator function, passing both parameters
    [fraction1 set_Numerator:3 Denominator:4];
    
    // Display our results
    printf(&amp;quot;Our Numerator: %i%c&amp;quot;, [fraction1 get_Numerator], '\n');
    printf(&amp;quot;Our Denominator: %i%c&amp;quot;, [fraction1 get_Denominator], '\n');
    printf(&amp;quot;Our Complete Fraction: &amp;quot;);
    [fraction1 print];

    // Release all of our claimed memory
    [fraction1 release];
}
&lt;/code&gt;&lt;/pre&gt;

The first thing to point out here is that the implementation files for Objective-C end in ".m" rather than ".c", as you might expect.  With that being said, if you have a background in C/C++, this basic structure will look very familiar - a header file depicting the API interface, an implementation file depicting the actual code for each method/function for that class, and a main driver file for controlling the flow of our program.&lt;br&gt;&lt;br&gt;

An additional difference I immediately noticed with the language was the numerous instances of "[..]" notation.  This is basically the way method/function calls are made in Objective-C, however they are referred to more as "sending messages".  You'll notice I provided a couple different examples above, some calling functions without passing any parameters (print) and other calls passing multiple parameters (set_Numerator:Denominator).&lt;br&gt;&lt;br&gt;

You may be asking yourself about now, okay great, I have the complete source to get me started on a simple example, but since you didn't use XCode, how on earth do I compile this thing?  Is it just like C/C++?  My answer, pretty darn close!  After some trial and error, here's the magic command I use for compiling:&lt;br&gt;

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;gcc -x objective-c -framework Foundation -lobjc main.m Fraction.m
&lt;/code&gt;&lt;/pre&gt;

If all goes well, you should see output precisely like this (including the line to execute the program):&lt;br&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ ./a.out
Our Numerator: 3
Our Denominator: 4
Our Complete Fraction: 3/4
&lt;/code&gt;&lt;/pre&gt;

I plan on creating a gradually more complex series of examples over time, so stay tuned!&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/01/objective-c-using-cocoa-framework-part.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-3477236463184319683?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/3477236463184319683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=3477236463184319683' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/3477236463184319683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/3477236463184319683'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/01/objective-c-using-cocoa-framework-part.html' title='Objective-C using the Cocoa Framework - Part 1'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-6728869310903793923</id><published>2008-01-05T21:56:00.000-08:00</published><updated>2008-01-06T09:10:35.300-08:00</updated><title type='text'>Facial Morphing &amp; Animation Using the Free Software - MorphX</title><content type='html'>I stumbled across this nifty little freeware the other week and finally got around to giving it a try.  For those of you who haven't tried morphing software before, the basic concept is to create a before and after photo, and tell the software to morph or tween between the two to make them seamlessly transform.&lt;br&gt;&lt;br&gt;

For this little demo, I took a couple webcam shots with some interesting effects and plopped those down for the before and after shots.  I took care to try and keep my head in relatively the same position between the shots.  This would likely make the transitions that much more believable.&lt;br&gt;&lt;br&gt;

I took a screenshot of the process of setting up the morph below.  You'll notice there is a dotted bright green (and blue where selected) line hovering over my face.  The idea is to click near key features on the before image.  Once complete, pressing enter would carry over that same line pattern to the after image.  From here you would simply adjust the vertices as necessary to maintain the key point landmark positions.&lt;br&gt;&lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_t4K3NwHabzM/R4EHF_ABBjI/AAAAAAAAADE/I0y04GmIAG4/s1600-h/Picture+1.png"&gt;&lt;img style="cursor: pointer;" src="http://4.bp.blogspot.com/_t4K3NwHabzM/R4EHF_ABBjI/AAAAAAAAADE/I0y04GmIAG4/s400/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5152407248080799282" border="0" /&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;

There's a built in preview feature to help you make sure your morphing sequence is looking good.  Once you're happy, you can either render the image sequence to several files or you can choose to render to movie (quicktime).  In my case, I rendered to quicktime and then took the movie into iMovie to further play with it, including your basic title screens as well as frame reversal effects and slow-motion :)&lt;br&gt;&lt;br&gt;

&lt;object width="320" height="266" class="BLOG_video_class" id="BLOG_video-a097ff3f012b87a9" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="movie" value="http://www.youtube.com/get_player"&gt;
&lt;param name="bgcolor" value="#FFFFFF"&gt;
&lt;param name="allowfullscreen" value="true"&gt;
&lt;param name="flashvars" value="flvurl=http://v7.nonxt6.googlevideo.com/videoplayback?id%3Da097ff3f012b87a9%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1330447885%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D864CA151CDFE966BE3F0EC503D38F7C127BBF41C.23F0CECC85B179FFEA21DF91536EEB0CAD29BD06%26key%3Dck1&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3Da097ff3f012b87a9%26offsetms%3D5000%26itag%3Dw160%26sigh%3DfYMjYwdZvv27yCIMaUdCmSgTd0g&amp;amp;autoplay=0&amp;amp;ps=blogger"&gt;
&lt;embed src="http://www.youtube.com/get_player" type="application/x-shockwave-flash"
width="320" height="266" bgcolor="#FFFFFF"
flashvars="flvurl=http://v7.nonxt6.googlevideo.com/videoplayback?id%3Da097ff3f012b87a9%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1330447885%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D864CA151CDFE966BE3F0EC503D38F7C127BBF41C.23F0CECC85B179FFEA21DF91536EEB0CAD29BD06%26key%3Dck1&amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3Da097ff3f012b87a9%26offsetms%3D5000%26itag%3Dw160%26sigh%3DfYMjYwdZvv27yCIMaUdCmSgTd0g&amp;autoplay=0&amp;ps=blogger"
allowFullScreen="true" /&gt;&lt;/object&gt;
&lt;br&gt;&lt;br&gt;

A really cool way of extending my example would be to daisy chain several facial morphs back to back.  You could for example take photos from your entire life and morph from one to the next chronologically, showing gradual age progression!  The possibilities are abundant and the software is free, so have fun!&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2008/01/facial-morphing-animation-using-free.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-6728869310903793923?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='enclosure' type='video/mp4' href='http://www.blogger.com/video-play.mp4?contentId=a097ff3f012b87a9&amp;type=video%2Fmp4' length='0'/><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/6728869310903793923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=6728869310903793923' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6728869310903793923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6728869310903793923'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2008/01/facial-morphing-animation-using-free.html' title='Facial Morphing &amp; Animation Using the Free Software - MorphX'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_t4K3NwHabzM/R4EHF_ABBjI/AAAAAAAAADE/I0y04GmIAG4/s72-c/Picture+1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-8635581674895329992</id><published>2007-12-31T09:39:00.000-08:00</published><updated>2008-01-01T00:48:15.783-08:00</updated><title type='text'>Regular expressions - Tools to assist the developer at heart.</title><content type='html'>I've been using regular expressions for a number of years in the workplace but am always keeping my eyes open for helpful tools (you can never have too many!).  I recently picked up a Mac as a second system at home and stumbled upon a cool little utility.  It's called RegExhibit.  Screenshots speak louder than words, so take a look at the following:&lt;br&gt;
&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_t4K3NwHabzM/R3n9m_ABBhI/AAAAAAAAAC0/2PPkQ5u9T7U/s1600-h/Picture%2B1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_t4K3NwHabzM/R3n9m_ABBhI/AAAAAAAAAC0/2PPkQ5u9T7U/s400/Picture%2B1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5150426495063229970" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
What I found really useful with this tool was the immediate feedback as you typed your regular expressions.  Another huge seller for me was the help files for this software, as it had a decently detailed collection all in one place (saving you the need to hunt down regex basics on the net).&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_t4K3NwHabzM/R3n99fABBiI/AAAAAAAAAC8/zgu-Juv7YC8/s1600-h/Picture%2B2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_t4K3NwHabzM/R3n99fABBiI/AAAAAAAAAC8/zgu-Juv7YC8/s400/Picture%2B2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5150426881610286626" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
And of course, this software is completely free, so it's hard to complain :).  For those of you Mac-less, another free web-based regular expression tool I typically turn to in the workplace is: http://www.regextester.com.
&lt;br&gt;&lt;br&gt;
&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/12/regular-expressions-tools-to-assist.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-8635581674895329992?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/8635581674895329992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=8635581674895329992' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8635581674895329992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8635581674895329992'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/12/regular-expressions-tools-to-assist.html' title='Regular expressions - Tools to assist the developer at heart.'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_t4K3NwHabzM/R3n9m_ABBhI/AAAAAAAAAC0/2PPkQ5u9T7U/s72-c/Picture%2B1.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-8301623249240576515</id><published>2007-12-08T21:32:00.000-08:00</published><updated>2008-01-16T09:38:21.182-08:00</updated><title type='text'>C# Generics - Performance Gain? Not so fast!</title><content type='html'>&lt;b&gt;UPDATE (1/16/08)&lt;/b&gt;: &lt;i&gt;A reader recently pointed out that I should not have used a data type of string for my tests due to it being a reference type, but rather used a value type such as int.  I would recommend referring to my new post located at &lt;a href="http://strainthebrain.blogspot.com/2008/01/c-generics-performance-gain-benchmarks.html"&gt;http://strainthebrain.blogspot.com/2008/01/c-generics-performance-gain-benchmarks.html&lt;/a&gt; for a more accurate benchmarking of generics versus non-generics :).&lt;/i&gt;&lt;br&gt;&lt;br&gt;

A friend of mine at work has been referencing some of the more spiffy features of the .NET 2.0 framework, one of which being &lt;b&gt;generics&lt;/b&gt;.  I thought they sounded interesting so I spent some time playing around with them and reading up on all of the fine-grain details.  There was one particular paragraph statement from Microsoft that I stumbled across on the MSDN documentation site (&lt;a href="http://msdn2.microsoft.com/en-us/library/ms379564(VS.80).aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms379564(VS.80).aspx&lt;/a&gt;) that stood out to me as they were comparing the non-generics versus generics approach:&lt;br&gt;&lt;br&gt;

&lt;i&gt;When using value types, you have to box them in order to push and store them, and unbox the value types when popping them off the stack. Boxing and unboxing incurs a significant performance penalty in their own right, but it also increases the pressure on the managed heap, resulting in more garbage collections, which is not great for performance either. Even when using reference types instead of value types, there is still a performance penalty because you have to cast from an Object to the actual type you interact with and incur the casting cost.&lt;/i&gt;&lt;br&gt;&lt;br&gt;

This statement sounded logical at the time, but I, being the geek that I am, wanted to put this statement to the test to see if it held water.  Unfortunately it not only didn't hold water, but it dried up like the Sahara Desert.  Take the following sample code pieces I put together:&lt;br&gt;&lt;br&gt;

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;namespace GenericsPerformance
{
    class Program
    {
        static void Main(string[] args)
        {
            string stringVal = &amp;quot;&amp;quot;;
            DateTime start, finish;
            TimeSpan mySpan;

           //Generics Test-------------------------------------------------------
           start = DateTime.Now;

           Stack&amp;lt;string&amp;gt; genStack = new Stack&amp;lt;string&amp;gt;();
           for (int i = 0; i &amp;lt; 1000000; i++)
               genStack.Push(&amp;quot;test&amp;quot; + i);
           for (int i = 0; i &amp;lt; 1000000; i++)
               stringVal = genStack.Pop();

           finish = DateTime.Now;

           mySpan = finish.Subtract(start);
           Console.WriteLine(&amp;quot;Gen Start: {0}\t Finish: {1}\t Timespan: {2}&amp;quot;, start.ToLongTimeString(), finish.ToLongTimeString(), mySpan.TotalMilliseconds.ToString ());
           //--------------------------------------------------------------------

           Console.ReadLine();
       }
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
Now compare the above code with the below code:&lt;br&gt;&lt;br&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;namespace NonGenericsPerformance
{
    class Program
    {
        static void Main(string[] args)
        {
            string stringVal = &amp;quot;&amp;quot;;
            DateTime start, finish;
            TimeSpan mySpan;

           //Non-generics Test---------------------------------------------------
           start = DateTime.Now;

           Stack nonGenStack = new Stack();
           for (int i = 0; i &amp;lt; 1000000; i++)
               nonGenStack.Push(&amp;quot;test&amp;quot; + i);
           for (int i = 0; i &amp;lt; 1000000; i++)
               stringVal = (string)nonGenStack.Pop();

           finish = DateTime.Now;

           mySpan = finish.Subtract(start);
           Console.WriteLine(&amp;quot;Non Start: {0}\t Finish: {1}\t Timespan: {2}&amp;quot;, start.ToLongTimeString(), finish.ToLongTimeString(), mySpan.TotalMilliseconds.ToString ());
           //--------------------------------------------------------------------

           Console.ReadLine();
       }
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;br&gt;
I ran a series of output tests, of which I'll post the results:&lt;br&gt;&lt;br&gt;
Gen Start: 3:45:01 PM    Finish: 3:45:03 PM      Timespan: 1659.3544&lt;br&gt;
Gen Start: 3:45:20 PM    Finish: 3:45:22 PM      Timespan: 1639.3874&lt;br&gt;
Gen Start: 3:46:02 PM    Finish: 3:46:03 PM      Timespan: 1626.9005&lt;br&gt;
&lt;br&gt;
Non Start: 3:43:25 PM    Finish: 3:43:27 PM      Timespan: 1601.653&lt;br&gt;
Non Start: 3:43:51 PM    Finish: 3:43:53 PM      Timespan: 1620.604&lt;br&gt;
Non Start: 3:44:21 PM    Finish: 3:44:22 PM      Timespan: 1604.9792&lt;br&gt;&lt;br&gt;

What's interesting to see here is the fact that the generics approach consistently under performs the non-generics approach for performing the exact same actions.  While this may vary from system to system, I found it quite surprising that it directly contradicted two of the main arguments in favor of using generics.&lt;br&gt;&lt;br&gt;
Bearing all of this in mind, assuming my ultimate need is not utmost performance, I prefer making use of generics simply because it helps in clarifying content being held within data structures and also simplifies the data retrieval process (no need for type-casting).&lt;br&gt;&lt;br&gt;
Ultimately, the point to keep in mind here is that generics may or may not gain you much in the way of performance, by eliminating the need for boxing/unboxing and typecasting.  Your mileage may vary.&lt;br&gt;&lt;br&gt;
&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/12/c-generics-performance-gain-not-so-fast.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-8301623249240576515?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/8301623249240576515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=8301623249240576515' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8301623249240576515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8301623249240576515'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/12/c-generics-performance-gain-not-so-fast.html' title='C# Generics - Performance Gain? Not so fast!'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-5423377565059596009</id><published>2007-11-27T16:57:00.000-08:00</published><updated>2007-11-27T17:41:37.297-08:00</updated><title type='text'>PGP Key Servers - The Yellowbook of People For Sending Encrypted Messages</title><content type='html'>Having previously played around with Seahorse (basically a gnome GUI application that sits over the top of GnuPG), I pondered what the point of generating my private and public keys were if nobody out there could independently obtain my public key for sending me messages.&lt;br&gt;&lt;br&gt;

Low and behold &lt;b&gt;Public Key Servers&lt;/b&gt;.  From the hour or so I spent playing around with them, there's one thing they have in common.  The ability to look for someone by their name or email address.  There are three popular Public Key Servers that are worth submitting your keys to:&lt;br&gt;&lt;br&gt;

&lt;a href="http://pgp.mit.edu"&gt;http://pgp.mit.edu&lt;/a&gt;&lt;br&gt;
&lt;a href="http://keyserver.veridis.com:11371"&gt;http://keyserver.veridis.com:11371&lt;/a&gt;&lt;br&gt;
&lt;a href="http://keyserver.pgp.com"&gt;http://keyserver.pgp.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;

If anyone out there knows more worth noting, please leave them in the comments and I'll certainly add them to the list.  After submitting my Public Key to each of these servers, within minutes my information was available for the world to grab.&lt;br&gt;&lt;br&gt;

From what I've read, many Public Key Servers seem to feed off of other ones, so once you're indexed in a few major ones, your information should spread to other lesser known ones, eventually making it fairly trivial to find you if someone wants to.&lt;br&gt;&lt;br&gt;

Just for fun I tried searching for some big security-buff names in the industry and managed to find key entries for folks like: Philip Zimmermann and Bruce Schneier.  The one thing I found confusing was the quantity of keys for a given person.  Sometimes you'll find people with 5 or even 10 key entries!  What's even more strange is that sometimes, none of their keys are set to expire.  I can only assume the user either forgot the pass phrase to their key pair or that they wanted to provide a more heavy-duty higher-bit key to scale with computing power.  I think the safest bet is to always pick the most recently dated key for a person.&lt;br&gt;&lt;br&gt;

This lead me to ponder, can you delete your entries from these servers?  Evidently the answer is "sort of".  Using what's called a "revocation" you can usually get your old key removed, but this is on a &lt;b&gt;per-server&lt;/b&gt; basis.  So the end result is you'd have to manually go to all the servers out there in the world with your information and update them (obviously not realistic).&lt;br&gt;&lt;br&gt;

I hope this has helped to provide a rough picture of what Public Key Servers are all about.&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/11/pgp-key-servers-yellowbook-of-people.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-5423377565059596009?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/5423377565059596009/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=5423377565059596009' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/5423377565059596009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/5423377565059596009'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/11/pgp-key-servers-yellowbook-of-people.html' title='PGP Key Servers - The Yellowbook of People For Sending Encrypted Messages'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-2344037622172581563</id><published>2007-11-18T08:34:00.000-08:00</published><updated>2007-12-31T17:07:42.957-08:00</updated><title type='text'>Have CAPTCHA systems met their OCR match?  I think not!</title><content type='html'>Oh the wonderful world of CAPTCHA systems!  You know what those are (maybe not by name, but you do!), those little annoying pictures you so-often have to fight with to prove you're a human being.&lt;BR&gt;&lt;BR&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_t4K3NwHabzM/R0BqPAkqpFI/AAAAAAAAABM/_0JSqbXIXw8/s1600-h/captcha.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_t4K3NwHabzM/R0BqPAkqpFI/AAAAAAAAABM/_0JSqbXIXw8/s400/captcha.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5134220381286736978" /&gt;&lt;/a&gt;

The sole purpose behind these little pests is simple, to keep automated spammers at bay.  They're frequently used most during account sign-ups and on comment-posting pages.&lt;BR&gt;&lt;BR&gt;

What you may or may not have wondered is why these pretty little pictures have gotten more and more difficult to actually read (even to the point where many sites offer the ability to click on a link to generate another CAPTCHA image because the first one isn't legible!).  As various computer languages evolve and programmers evolve with them, writing systems that analyze images and apply some optical character recognition (OCR) becomes easier by the day.&lt;BR&gt;&lt;BR&gt;

I have seen some recent hype about an OCR system called tesseract-ocr.  What's interesting is this hype surrounds an OCR system written back in the early-to-mid 90s.  In fact, nobody has really made any improvements on the system since 1995!  I was scratching my head about this one, if nobody has made any improvements, surely this thing can't be that great, at least not for the purposes of dismantling the bleeding edge CAPTCHA image.&lt;BR&gt;&lt;BR&gt;

In order to play around with the tesseract-ocr libraries, the only real requirement was that I feed the command line tif or mdi images.  Seeing as most (if not all) of the CAPTCHA images I came across were gifs and jpgs, I wanted an automated way of converting them to tifs, so I put together a magical 4 liner to do basically just that (didn't bother with parsing the image name from the command args, but that would be the next logical step).&lt;BR&gt;&lt;BR&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#! /usr/bin/env python
from PIL import Image

im = Image.open(&amp;quot;images/follow.jpg&amp;quot;)
im.save(&amp;quot;images/follow.tif&amp;quot;,&amp;quot;TIFF&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
Once saved, a magical call to tesseract later and I was on my merry way.  What followed started as sheer excitement.  I fed tesseract the overly-used example "fnord" image, and voila, the results were exactly as expected, "fnord" popped out in the resulting text file.&lt;br&gt;&lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_t4K3NwHabzM/R0BtlgkqpJI/AAAAAAAAABs/_6QAR5wHtJ8/s1600-h/fnord.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_t4K3NwHabzM/R0BtlgkqpJI/AAAAAAAAABs/_6QAR5wHtJ8/s400/fnord.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5134224066368677010" /&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;

I then ramped it up with a couple more cutting edge CAPTCHAs and was sorely disappointed.  The following 2 images resulted in text output completely garbled up, with question marks and all sorts of fun!&lt;BR&gt;&lt;BR&gt;
&lt;center&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_t4K3NwHabzM/R0BrLQkqpGI/AAAAAAAAABU/0o41qPuqQgs/s1600-h/Captcha.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_t4K3NwHabzM/R0BrLQkqpGI/AAAAAAAAABU/0o41qPuqQgs/s400/Captcha.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5134221416373855330" /&gt;&lt;/a&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_t4K3NwHabzM/R0BrZwkqpHI/AAAAAAAAABc/Rvq-044JesM/s1600-h/follow.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_t4K3NwHabzM/R0BrZwkqpHI/AAAAAAAAABc/Rvq-044JesM/s400/follow.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5134221665481958514" /&gt;&lt;/a&gt;&lt;/center&gt;
&lt;br&gt;&lt;br&gt;
End conclusion being that all of the hype surrounding this lovely OCR is well-deserved if you're wanting to convert a scanned newspaper or book into text, but it doesn't have a chance, in you know what, of keeping up with todays CAPTCHA systems.  They're getting to the point where text is no longer the answer, but object analysis is (a MUCH trickier feat to circumvent).  I will leave you with an example of the "next generation" of CAPTCHAs.  Until next time...&lt;br&gt;&lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_t4K3NwHabzM/R0BsZgkqpII/AAAAAAAAABk/PNVXbM7eghk/s1600-h/kitten_captcha.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_t4K3NwHabzM/R0BsZgkqpII/AAAAAAAAABk/PNVXbM7eghk/s400/kitten_captcha.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5134222760698619010" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;

&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/11/have-captcha-systems-met-their-ocr.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-2344037622172581563?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/2344037622172581563/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=2344037622172581563' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/2344037622172581563'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/2344037622172581563'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/11/have-captcha-systems-met-their-ocr.html' title='Have CAPTCHA systems met their OCR match?  I think not!'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_t4K3NwHabzM/R0BqPAkqpFI/AAAAAAAAABM/_0JSqbXIXw8/s72-c/captcha.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-3968500302999348141</id><published>2007-11-11T20:10:00.000-08:00</published><updated>2007-11-11T20:23:15.143-08:00</updated><title type='text'>Further Analysis of Keywords in Movie Titles</title><content type='html'>After exploring the common keywords in action movies, I wanted to compare results against a different genre of film.  I thought comedy would be interesting.  The following graph (which you can click on) depicts results with the same keyword set, but against a much larger quantity of films (95,642 to be precise).
&lt;br&gt;&lt;br&gt;
A top 3 keyword comparison between comedy and action is as follows:
&lt;Br&gt;&lt;br&gt;
&lt;b&gt;Comedy&lt;/b&gt;&lt;br&gt;
1. love&lt;br&gt;
2. war&lt;br&gt;
3. sex&lt;br&gt;
&lt;br&gt;
&lt;b&gt;Action&lt;/b&gt;&lt;br&gt;
1. war&lt;br&gt;
2. kill&lt;br&gt;
3. blood&lt;br&gt;
&lt;br&gt;
One can only wonder if "war" would make it in the top 3 for children's movies too, odd!&lt;br&gt;&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_t4K3NwHabzM/RzfTvBhqF9I/AAAAAAAAABE/_y18T1PkFD8/s1600-h/pychart2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_t4K3NwHabzM/RzfTvBhqF9I/AAAAAAAAABE/_y18T1PkFD8/s400/pychart2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5131803105228888018" /&gt;&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/11/further-analysis-of-keywords-in-movie.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-3968500302999348141?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/3968500302999348141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=3968500302999348141' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/3968500302999348141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/3968500302999348141'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/11/further-analysis-of-keywords-in-movie.html' title='Further Analysis of Keywords in Movie Titles'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_t4K3NwHabzM/RzfTvBhqF9I/AAAAAAAAABE/_y18T1PkFD8/s72-c/pychart2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-8922458572611269305</id><published>2007-11-10T20:34:00.000-08:00</published><updated>2007-12-31T17:12:19.185-08:00</updated><title type='text'>Statistical Analysis of Keywords in Movie Titles</title><content type='html'>I felt experimental this evening and was wanting to dive into some modules enabling me to graph data in Python.  This started out as a "hey, that's cool, graphs...those can be useful".  Several hours later, it turned into "wow, there's some potential application here and this is a very cool view over such a large set of data...".
&lt;br&gt;&lt;br&gt;
You'll notice in this resulting graph that I have tried to choose "common thematic" words, enabling us to have deep insight into the history of action movie naming conventions.  I would like to cross-reference these results with the year the movies were created.  It would be even more interesting to overlap those create dates with a historical time line of major events to see how heavily movie naming conventions are influenced by current events.
&lt;br&gt;&lt;br&gt;
On a more technical note, I generated this graph using the pychart module, amongst more common ones.  Graph and associated code to follow :)
&lt;br&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_t4K3NwHabzM/RzaIgxhqF8I/AAAAAAAAAA8/d26IYLS6ZDg/s1600-h/pychart1.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_t4K3NwHabzM/RzaIgxhqF8I/AAAAAAAAAA8/d26IYLS6ZDg/s400/pychart1.png" alt="" id="BLOGGER_PHOTO_ID_5131438922066958274" border="0" /&gt;&lt;/a&gt;
&lt;br&gt;
&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#! /usr/bin/env python
 
#Copyright (C) 2007  Christopher M. Ball (chris.m.ball@gmail.com)
#Originally Posted At: &amp;lt;http://strainthebrain.blogspot.com&amp;gt;
#
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published
#by the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
#the GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.

from pychart import *
import commands, pdb, operator

theme.use_color = True
theme.reinitialize()
theme.get_options()

#This function obtains grep counts for each of our keywords against our data file, returning them in coordinate pairs
def keyworddata():
   keywords = ['love','sex','war','money','god','murder','kill','mission','journey','freedom']
   keywords += ['happy','blood','steal','travel','fun','sad','power','peace','drug','friend']
   keywords += ['marriage','country','patriot','tax','prison']
   results = []
   
   #For each keyword, perform a grep count, then form our keyword/value tuple
   for currentWord in keywords:
       ycount = commands.getstatusoutput(&amp;quot;grep -i -c &amp;quot; + currentWord + &amp;quot; movielist.txt&amp;quot;)
       results.append((currentWord, int(ycount[1])))
   
   return results                        

#Setting up the tick and axis
tick = tick_mark.Circle(size=10, fill_style=fill_style.red)
xaxis = axis.X(label=&amp;quot;Movie Title Keyword&amp;quot;)
yaxis = axis.Y(label=&amp;quot;Quantity of Action Movies (23,530 total)&amp;quot;)

#Before assigning my results from the function, I sort the resulting list of tuples by the 2nd item of each pair, descending.
plotpoints = sorted(keyworddata(), key=operator.itemgetter(1), reverse=1)

#Setting up and binding our data with graph settings
ar = area.T(x_coord = category_coord.T(plotpoints, 0), x_axis=xaxis, y_axis=yaxis, x_grid_interval=20, y_grid_interval=25, size=(1000,600), legend=None, y_range = (0, 450))
ar.add_plot(line_plot.T(data = plotpoints, tick_mark=tick))
ar.draw()
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/11/statistical-analysis-of-keywords-in.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-8922458572611269305?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/8922458572611269305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=8922458572611269305' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8922458572611269305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/8922458572611269305'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/11/statistical-analysis-of-keywords-in.html' title='Statistical Analysis of Keywords in Movie Titles'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_t4K3NwHabzM/RzaIgxhqF8I/AAAAAAAAAA8/d26IYLS6ZDg/s72-c/pychart1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-6086170824944867752</id><published>2007-11-10T08:40:00.000-08:00</published><updated>2007-12-31T17:18:32.386-08:00</updated><title type='text'>Python Script For Collecting Movie Genres From IMDB</title><content type='html'>I have been working on and off with a colleague of mine for the past (6 months?) on the http://www.netflixprize.com competition.  We ran into some road blocks a while back and I had always wished we were provided more data for the movies.  Some may argue no additional data should be necessary for the competition.  The puritan in me agrees, but I would still appreciate more data nevertheless :)

While I do not believe IMDB appreciates users screen scraping data, I provide this purely for &lt;span style="font-weight:bold;"&gt;educational purposes only&lt;/span&gt;.

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#! /usr/bin/env python
  
#Copyright (C) 2007  Christopher M. Ball (chris.m.ball@gmail.com)
#Originally Posted At: &amp;lt;http://strainthebrain.blogspot.com&amp;gt;
#
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published
#by the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
#the GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.
 
import urllib, re, commands
 
#Alphabet list
alpha = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
 
for letter in alpha:
    #The following few lines retrieves the full html source of the homepage
    websiteURL = &amp;quot;http://imdb.com/TitlesByGenres?genres=Action&amp;amp;start=&amp;quot; + letter + &amp;quot;&amp;amp;nav=/Sections/Genres/Action/include-titles&amp;quot;
    fileObj = urllib.urlopen(websiteURL)
    html = fileObj.read()
 
    #Collection like '&amp;lt;TD WIDTH=&amp;quot;95%&amp;quot;&amp;gt;&amp;lt;A HREF=&amp;quot;/title/tt0431641/&amp;quot;&amp;gt;Azumi 2: Death or Love (2005)&amp;lt;/A&amp;gt;&amp;lt;/TD&amp;gt;'
    list = re.findall(&amp;quot;&amp;lt;TD WIDTH=\&amp;quot;95%\&amp;quot;&amp;gt;&amp;lt;A HREF=.*?&amp;lt;/TD&amp;gt;&amp;quot;,html)
 
    #Opening a file for writing to in append mode
    f=open('movielist.txt', 'a')
 
    #Taking a slice of each line and cleaning up some inconsistencies
    for item in list:
        f.write(item[44:-9].replace('&amp;quot;','') + &amp;quot;\r\n&amp;quot;
 
print &amp;quot;Completed&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/11/python-script-for-collecting-movie.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-6086170824944867752?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/6086170824944867752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=6086170824944867752' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6086170824944867752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6086170824944867752'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/11/python-script-for-collecting-movie.html' title='Python Script For Collecting Movie Genres From IMDB'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-3269547305289285722</id><published>2007-11-08T22:29:00.000-08:00</published><updated>2007-11-11T14:12:19.035-08:00</updated><title type='text'>Python Script to Download Latest Dilbert Strip &amp; Auto-launch in Image Viewer</title><content type='html'>I wanted to learn more about the urllib module so I thought it would be nifty to write a little script that could be double clicked from my desktop and auto-magically display the Dilbert comic strip for the current day.

I have placed comments throughout and I hope this teaches others something as well.

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;#! /usr/bin/env python&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;#Copyright (C) 2007  Christopher M. Ball (chris.m.ball@gmail.com)&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="rem"&gt;#Originally Posted At: &amp;lt;http://strainthebrain.blogspot.com&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="rem"&gt;#&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="rem"&gt;#This program is free software: you can redistribute it and/or modify&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="rem"&gt;#it under the terms of the GNU General Public License as published&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="rem"&gt;#by the Free Software Foundation, either version 3 of the License, or&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="rem"&gt;#(at your option) any later version.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="rem"&gt;#&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="rem"&gt;#This program is distributed in the hope that it will be useful,&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="rem"&gt;#but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;&lt;span class="rem"&gt;#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;&lt;span class="rem"&gt;#the GNU General Public License for more details.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&lt;span class="rem"&gt;#&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;&lt;span class="rem"&gt;#You should have received a copy of the GNU General Public License&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&lt;span class="rem"&gt;#along with this program.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;import urllib, re, commands&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;&lt;span class="rem"&gt;#The following few lines retrieves the full html source of the homepage&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;websiteURL = &lt;span class="str"&gt;"http://www.dilbert.com"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;fileObj = urllib.urlopen(websiteURL)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;html = fileObj.read()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;&lt;span class="rem"&gt;#Using some regular expressions to help narrow down the interested image path&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;uncleanFile = re.findall(&lt;span class="str"&gt;"Attachments=/comics/dilbert/archive/images.*?&amp;amp;"&lt;/span&gt;, html)[0]&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;&lt;span class="rem"&gt;#Cleaning up the path for precise retrieval&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;cleanFile = &lt;span class="str"&gt;"http://www.dilbert.com"&lt;/span&gt; + uncleanFile[12:-1]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;&lt;span class="rem"&gt;#Storing the current dilbert graphic to my computer&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; re.search(&lt;span class="str"&gt;".gif"&lt;/span&gt;,cleanFile):&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;    urllib.urlretrieve(cleanFile, &lt;span class="str"&gt;"dailydilbert.gif"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;    commands.getstatusoutput(&lt;span class="str"&gt;"gthumb dailydilbert.gif"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;elif re.search(&lt;span class="str"&gt;".jpg"&lt;/span&gt;,cleanFile):&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;    urllib.urlretrieve(cleanFile, &lt;span class="str"&gt;"dailydilbert.jpg"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;    commands.getstatusoutput(&lt;span class="str"&gt;"gthumb dailydilbert.jpg"&lt;/span&gt;)&lt;/pre&gt;
&lt;/div&gt;
&lt;br&gt;&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/11/python-script-to-download-latest.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-3269547305289285722?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/3269547305289285722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=3269547305289285722' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/3269547305289285722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/3269547305289285722'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/11/python-script-to-download-latest.html' title='Python Script to Download Latest Dilbert Strip &amp; Auto-launch in Image Viewer'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-6147172058786075011</id><published>2007-11-04T20:15:00.000-08:00</published><updated>2007-11-11T14:13:19.600-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='disk usage'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='script'/><title type='text'>Python Script For Calculating Disk Size In Bytes &amp; Gigabytes</title><content type='html'>I saw some posts on the ubuntu forums inquiring as to how someone might use Python to calculate the size of all mounted disks on their system.  I thought this would be an excellent exercise in practicing several concepts, including calling a built-in linux command, consuming that output, parsing out the data we were interested in using, constructing calculations from it, then displaying the final results.

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;#! /usr/bin/env python&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;import commands&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;diskusage = commands.getstatusoutput(&lt;span class="str"&gt;"df -a"&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;listvals = diskusage[1].split()[8:-1:6]&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;sum = 0&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; val &lt;span class="kwrd"&gt;in&lt;/span&gt; listvals:&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    sum += int(val)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;print &lt;span class="str"&gt;"Disk Size"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;print &lt;span class="str"&gt;"---------"&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;print str(sum) + &lt;span class="str"&gt;" Bytes"&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;print str(int(sum) / 1024 / 1024) + &lt;span class="str"&gt;" GB"&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;br&gt;&lt;br&gt;
Disk Size&lt;br&gt;
---------&lt;br&gt;
76528052 Bytes&lt;br&gt;
72 GB&lt;br&gt;
&lt;br&gt;
The one highlight of the above code that I enjoyed the most was line 6.  First I split up the data I wanted to work with into individual strings.  I then examined that data and determined that I wanted to take a snazzy "slice" starting at the 8th index, going all the way to the end of the string, grabbing every 6th element along the way!  After experimenting with slicing, I must say that I am extremely jealous we don't have this feature in the land of C#, very powerful stuff!
&lt;br&gt;&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/11/python-script-for-calculating-disk-size.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-6147172058786075011?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/6147172058786075011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=6147172058786075011' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6147172058786075011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/6147172058786075011'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/11/python-script-for-calculating-disk-size.html' title='Python Script For Calculating Disk Size In Bytes &amp; Gigabytes'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-4080532837334250720</id><published>2007-11-04T14:46:00.001-08:00</published><updated>2007-11-11T14:14:20.176-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='function'/><category scheme='http://www.blogger.com/atom/ns#' term='wxpython'/><category scheme='http://www.blogger.com/atom/ns#' term='class'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Python Using the wxPython GUI Toolkit</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_t4K3NwHabzM/Ry5Qdwy4-lI/AAAAAAAAAAc/ltLY8RCW-kk/s1600-h/Screenshot-Chris%27+Notepad.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://4.bp.blogspot.com/_t4K3NwHabzM/Ry5Qdwy4-lI/AAAAAAAAAAc/ltLY8RCW-kk/s200/Screenshot-Chris%27+Notepad.png" alt="" id="BLOGGER_PHOTO_ID_5129125497866353234" border="0" /&gt;&lt;/a&gt;I recently picked up an excellent book titled "Beginning Python, From Novice to Professional" by Magnus Lie Hetland.  So far, this book has turned out to be a very practical read with some solid examples.  While I will certainly be churning out some original code in the near future, I thought this might be a very helpful starting place for many people out there, as it gives a small glimpse at many concepts for this language, including functions, event handlers, and button/textbox declarations using the lovely wxPython GUI Toolkit.  For my own sanity, I have made some slight changes to the original source and placed my own embedded comments throughout the code to help explain each line of the code.
&lt;br&gt;&lt;br&gt;
If you're curious, this miniature notepad application does indeed work! :)
&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
 font-size: small;
 color: black;
 font-family: Consolas, "Courier New", Courier, Monospace;
 background-color: #ffffff;
 /*white-space: pre;*/
}

.csharpcode pre { margin: 0em; }

.csharpcode .rem { color: #008000; }

.csharpcode .kwrd { color: #0000ff; }

.csharpcode .str { color: #006080; }

.csharpcode .op { color: #0000c0; }

.csharpcode .preproc { color: #cc6633; }

.csharpcode .asp { background-color: #ffff00; }

.csharpcode .html { color: #800000; }

.csharpcode .attr { color: #ff0000; }

.csharpcode .alt 
{
 background-color: #f4f4f4;
 width: 100%;
 margin: 0em;
}

.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;div class="csharpcode"&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;#! /usr/bin/env python&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;#Library imports&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;import wx&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="rem"&gt;#Open file function&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;def openFile(event):&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    file = open(filename.GetValue())&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    contents.SetValue(file.read())&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    file.close()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="rem"&gt;#Save file function&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;def saveFile(event):&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;    file = open(filename.GetValue(),&lt;span class="str"&gt;'w'&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;    file.write(contents.GetValue())&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;    file.close()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&lt;span class="rem"&gt;#Application object initialization&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;app = wx.App()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;&lt;span class="rem"&gt;#Creating main window frame that contains everything&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;win = wx.Frame(None, title=&lt;span class="str"&gt;"Chris' Notepad"&lt;/span&gt;, size=(410, 335))&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;&lt;span class="rem"&gt;#Creating a child background panel of our main window&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;bkg = wx.Panel(win)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;&lt;span class="rem"&gt;#Declaring the buttons and textboxes for the notepad application&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;loadButton = wx.Button(bkg, label=&lt;span class="str"&gt;'Open'&lt;/span&gt;)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;loadButton.Bind(wx.EVT_BUTTON, openFile)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;saveButton = wx.Button(bkg, label=&lt;span class="str"&gt;'Save'&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;saveButton.Bind(wx.EVT_BUTTON, saveFile)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;filename = wx.TextCtrl(bkg)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;contents = wx.TextCtrl(bkg, style=wx.TE_MULTILINE | wx.HSCROLL)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;&lt;span class="rem"&gt;#Creating a boxsizer container to hold some objects for alignment&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;hbox = wx.BoxSizer()&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;hbox.Add(filename, proportion=1, flag=wx.EXPAND)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;hbox.Add(loadButton, proportion=0, flag=wx.LEFT, border=5)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;hbox.Add(saveButton, proportion=0, flag=wx.LEFT, border=5)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;&lt;span class="rem"&gt;#Creating a second boxsizer container to hold the hbox in addition to the contents object.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;&lt;span class="rem"&gt;#This enables us to align everything into the vbox boxsizer, which we'll then bind.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;vbox = wx.BoxSizer(wx.VERTICAL)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;vbox.Add(hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;vbox.Add(contents, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, border=5)&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;&lt;span class="rem"&gt;#Setting the window to make use of the vbox layout sizer.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;bkg.SetSizer(vbox)&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;&lt;span class="rem"&gt;#Makes sure the window is shown when the application is started.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;win.Show()&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;&lt;span class="rem"&gt;#Executing the main GUI event loop&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;app.MainLoop()&lt;/pre&gt;
&lt;/div&gt;
&lt;br&gt;&lt;script type="text/javascript"&gt;
digg_url = 'http://strainthebrain.blogspot.com/2007/11/python-using-wxpython-gui-toolkit.html';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-4080532837334250720?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/4080532837334250720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=4080532837334250720' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/4080532837334250720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/4080532837334250720'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/11/python-using-wxpython-gui-toolkit.html' title='Python Using the wxPython GUI Toolkit'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_t4K3NwHabzM/Ry5Qdwy4-lI/AAAAAAAAAAc/ltLY8RCW-kk/s72-c/Screenshot-Chris%27+Notepad.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-431639831826562193</id><published>2007-10-31T22:18:00.000-07:00</published><updated>2007-11-04T16:50:52.350-08:00</updated><title type='text'>Seahorse and PGP Encryption</title><content type='html'>I was exploring some packages for playing around with PGP encryption and stumbled across Seahorse. Seems like a nifty little GUI application that sits over the top of the Gnu Privacy Guard (GPG). I've gone through the process of generating my public key for anyone interested in sending me secret messages. If you'd like to have me send you back an encrypted message, please provide me with your public key as well and I'd be glad to do so!

I've pondered for a few years now why the world hasn't turned more hi-tech in this arena, especially considering the numerous issues with privacy these days.

&lt;pre&gt;
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.6 (GNU/Linux)

mQGiBEcpWPwRBADIv2jcCj9kbzUV/ww+Zw1/qwUZslNBfzIjnII8FCsr8WY+iIOK
PQfWCNuDjrvEX2jkucSlog/h9r4TvbGXCpG/ivhF/vLnFPJCUWWiTlln//14NvWh
kUs5U5BUgjDFWgUiFAr7yz6VZZPhtszcxnNJqHEvwGGiMTiEj/xt87jQWwCg1kTb
cGLd0z0ysT8IFtcOHiTGzEkEALkE+dOKBXkCg3vsj58AWIYCiApDkyGUFW0dvCt3
dNxdZLyYS3ab0Tl7BEUHGBWZxZAOlvAKeqg4MupqEsoMIFt42GKOpnPJc1cl6M0J
PByMyycbzNEZWgnh+vhnFw8MpqKarPAQMH12aNWABML7zg3d31zVbVrBQeQrSPmZ
17bDA/4h1NPC8C97HFTV751mezHzC8jR3/JRvwn2qBFBiSEMDTMuF5yLzv1oPHoe
FCdmUDZnzOW47ie2YFeqTsTh8rrTTOowJILgPL3zuIj+DSp33HJKVrRM/oEMQDEz
JqUeBL6U1BglpXZ4T/ucxmVqdQ5I4pD0GzAh4QA6JV1nQQOC27QsQ2hyaXN0b3Bo
ZXIgTS4gQmFsbCA8Y2hyaXMubS5iYWxsQGdtYWlsLmNvbT6IYAQTEQIAIAUCRylY
/AIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJELJroN4Ln9TOMCgAnR99rdKY
xDzjfCaQUQ5ic2jbcNU8AJwPlxqi04wV+YboL/+H3BVQ0Wp2srkCDQRHKVkBEAgA
gSPbzlNpI6dvskdlvHgcGAkkQkN2WrcqOj3tiy6cr7bWlPfGdyUft6I6Gh6JJ4n9
eWAlwfgXzjeI6L6gZD8b6aWg0W9xKNSEhE4nx7UmrjcmCURe9JJzYjLUhjVLwbyS
7CIA8OC24QLje8ofrfJjmvaEDzgZ6zlIF6U16qAihy8IiMNb56+CGREonXrGi3KJ
7em7PW30JnnCfQvc9lAu+N/IwKXrgG6LN38A7zH6lRq5giuyTzFIOGn2FRmnKGRZ
Y6Zlud7vEuSKzhW09DHMBhcnq8HH02r/aWVOjb9cWQS8PPSmehg/pf8RICt9bnUC
fmzWh2YQLFoDZxStNOrpBwADBQf/WxTjbCWHPPlQGPinXfZwoyimt1vpkoxLzJG9
v4wnrDEGXUxTcNI4fDY8ZAAgtcfkCeGZBGX1y3ExxqMZd0U9HumfB/QP8MyKKAka
JRJV0Jry+/tqdaGkXRGrfNUUKgX244Rtci49xFl+jdYFFkhY+LazcZT3wgYfH1eo
fOE8ZB8xJmb16kLDzOasj/8stZs+2Va+L5YNfJvDiXO6/5xiFvI9RLcx+edIHLeI
Uc2DerE6Mnu6Q1sC1Y3DxQJcSEzMXDsph6BC0E1BKZ07G3eYhC1rSRkc3ARJq+gf
NTA2Zi+2K2BJ1DDeriYtXlRqGwc/Bq6kNEV9gbqB9bs4zpRia4hJBBgRAgAJBQJH
KVkBAhsMAAoJELJroN4Ln9TOjK4AoLyHQN3KRR/lIjywElKW/SyfUl2eAKCRVeCe
dbpcrPnH7T5VE6k/0hioJg==
=hx/m
-----END PGP PUBLIC KEY BLOCK-----
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-431639831826562193?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/431639831826562193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=431639831826562193' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/431639831826562193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/431639831826562193'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/10/seahorse-and-pgp-encryption.html' title='Seahorse and PGP Encryption'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4668281529795694673.post-1962189303229414101</id><published>2007-10-31T17:42:00.000-07:00</published><updated>2007-10-31T17:53:40.923-07:00</updated><title type='text'>Python IDE's With Intellisense?</title><content type='html'>After scouring the net for hours last night, I was determined to figure out if there were any &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;IDE's&lt;/span&gt; out there offering equivalent &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Intellisense&lt;/span&gt; / Auto-completion to that of Visual Studio.  To my surprise, this turned out to be a rather disappointing search.

I installed 3 different &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;IDE's&lt;/span&gt; capable of running on my current home system running &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Ubuntu&lt;/span&gt; 7.10.  I tried out &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;Geany&lt;/span&gt;, IDLE, and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;PIDA&lt;/span&gt;.  While all of the &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_6"&gt;aforementioned&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;IDE's&lt;/span&gt; have some wonderful features, none of them offered smooth informative &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Intellisense&lt;/span&gt; like I'm use to working with in Visual Studio.  The &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;IDE&lt;/span&gt; that came closest was IDLE, offering a somewhat weak package-like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;Intellisense&lt;/span&gt; if you're typing at the Python prompt.  Unfortunately, this doesn't bode well for my needs.

This led me to thinking about the complexities of how one would write &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;Intellisense&lt;/span&gt; for a dynamic language such as Python, where type declaration isn't determined until &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_12"&gt;run time&lt;/span&gt;.  This ends up being a chicken and egg situation.  You can't display available functions / properties for a given object if you don't yet know its type.  This would imply that the only solution would be to have a tiered-like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;Intellisense&lt;/span&gt; where you'd have to click on the proposed "type" you'd like to display &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;Intellisense&lt;/span&gt; for.  I'd envision users would have to be able to assist the "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;Un&lt;/span&gt;"&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;intellisense&lt;/span&gt; if you will ;).

For the time being, I will chock this up to being one of the pitfalls of using such a flexible language, you take a hit at the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;IDE&lt;/span&gt; level.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4668281529795694673-1962189303229414101?l=strainthebrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strainthebrain.blogspot.com/feeds/1962189303229414101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4668281529795694673&amp;postID=1962189303229414101' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/1962189303229414101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4668281529795694673/posts/default/1962189303229414101'/><link rel='alternate' type='text/html' href='http://strainthebrain.blogspot.com/2007/10/python-ides-with-intellisense.html' title='Python IDE&apos;s With Intellisense?'/><author><name>Christopher M. Ball</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_t4K3NwHabzM/TREXuRee9TI/AAAAAAAAAW8/P9WwVUQ2-Y8/S220/snapshot_square.jpg'/></author><thr:total>2</thr:total></entry></feed>
