<?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-19895055</id><updated>2012-02-16T12:17:22.057-08:00</updated><title type='text'>Devin Venable</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>83</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-19895055.post-869831578445882529</id><published>2012-02-10T12:01:00.000-08:00</published><updated>2012-02-15T09:41:01.305-08:00</updated><title type='text'>Badges</title><content type='html'>We've been experimenting with badges for the SayAh web site.  For example, the following badge---which is just a hyperlink with an embedded image---directs visitors to the CSOS web site to Bryan Hawkin's SayAh Review Site.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sayah.com/doctor/orthopedic-surgery/ok/tulsa/bryan-j-hawkins/8/" target="_blank"&gt;&lt;img src="http://www.sayah.com/static/images/MyReviewsButt.png" alt="SayAh Review Results" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'm not sure if the badge fragment will render properly within a blogger post, thus this post, which tests behavior.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-869831578445882529?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/869831578445882529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=869831578445882529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/869831578445882529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/869831578445882529'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2012/02/badges.html' title='Badges'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-782141314814747049</id><published>2011-09-21T08:50:00.000-07:00</published><updated>2011-09-21T08:51:55.657-07:00</updated><title type='text'>git differences between working copy and stashed copy</title><content type='html'>&lt;div&gt;Shows the differences between copy and third item in the stash stack...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;git diff stash@{3}&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-782141314814747049?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/782141314814747049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=782141314814747049' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/782141314814747049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/782141314814747049'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/09/git-differences-between-working-copy.html' title='git differences between working copy and stashed copy'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-3372863795009735174</id><published>2011-09-12T08:53:00.000-07:00</published><updated>2011-09-12T08:58:23.367-07:00</updated><title type='text'>Vim search and replace from current location to end of file</title><content type='html'>Instead of searching and replacing the entire file with...&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;:s/old/new/g&lt;/div&gt;&lt;div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Try inserting ".," just after the colon.  This means "from current position to end of file".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;div&gt;&lt;br /&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;:.,s/old/new/g&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The comma actually specifies a range to make the substitution, from left and right of comma.  For example...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;:5,10s/old/new/g&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;...makes the substitutions on lines 5 through 10.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-3372863795009735174?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/3372863795009735174/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=3372863795009735174' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3372863795009735174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3372863795009735174'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/09/vim-search-and-replace-from-current.html' title='Vim search and replace from current location to end of file'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4899541889252413956</id><published>2011-09-09T09:02:00.000-07:00</published><updated>2011-09-09T09:07:29.518-07:00</updated><title type='text'>Notice to .NET developers</title><content type='html'>Word is there are about 30 more JAVA positions that need to be filled in the Tulsa area than there are JAVA capable developers.  This is driving up the rate that JAVA developers can demand.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Meanwhile, Tulsa is flooded with .NET developers, which drives the rate .NET developers demand, downward.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So a word to the wise:  don't get married to one vendor's technology.  Any software engineer worth his salt can switch from .NET to JAVA or visa-versa without much pain.  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4899541889252413956?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4899541889252413956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4899541889252413956' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4899541889252413956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4899541889252413956'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/09/notice-to-net-developers.html' title='Notice to .NET developers'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6582858239862130369</id><published>2011-08-31T07:14:00.000-07:00</published><updated>2011-08-31T12:40:38.414-07:00</updated><title type='text'>Vim tags</title><content type='html'>Continuing on with my exploration of Vim features I've yet to use, let's explore tags.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Tags are like bookmarks.  They let you jump around to different places in your file that you might want to reference, like a class definition for example.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Create a tag like so:  ":tag tagname".  This tags the current line number with the name you provide.  Alternatively, you can use the shortcut CTRL + ].  The tag name will be taken from either the character under your cursor, or if you've highlighted a word or phrase, it will be used.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;":tags" shows you your list of tags.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;:tags&lt;/div&gt;&lt;div&gt;  # TO tag         FROM line  in file/text&lt;/div&gt;&lt;div&gt;&amp;gt; 1  1 LongTextAnswer      8  q = LongTextAnswer()&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Each time I show my :tags I get this error:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;E433: No tags file.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This may also explain why my tags queue only contains the most recent tag I create.  Further reading reveals that the tags file is created by the program ctags&lt;i&gt;.  &lt;/i&gt;I'll try installing exuberant-ctags and see what affect that has on my operation.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;pre&gt;sudo apt-get install exuberant-ctags&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Restarting vim and trying the :tags command again showed that my tags file could still not be found.  I found a nice little page that describes the rest of the process that one must go through to get your tags file set up.  Follow the link to learn more.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://amix.dk/blog/post/19329"&gt;http://amix.dk/blog/post/19329&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On a related note, you can read ctags in python:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://code.google.com/p/python-ctags/"&gt;http://code.google.com/p/python-ctags/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6582858239862130369?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6582858239862130369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6582858239862130369' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6582858239862130369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6582858239862130369'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/08/vim-tags.html' title='Vim tags'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-5512836451579657392</id><published>2011-08-31T06:51:00.000-07:00</published><updated>2011-08-31T07:09:38.959-07:00</updated><title type='text'>Vim Execute Mode</title><content type='html'>I use vim and gvim every day.  I'm so productive using the small subset of available commands that I know that I tend not to explore the question, "what else can I do with Vim?"&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Take Execute Mode for example.  In 10 years of Vim use, I've never tried it.  Let's fix that now.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You enter Execute Mode by pressing capital Q (shift + q) when in normal mode.  You'll see this at the bottom of your window.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Entering Ex mode.  Type "visual" to go to Normal mode.&lt;/div&gt;&lt;div&gt;:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This seems familiar enough, but this is different than when you simply type ":" to enter a command at the bottom of the screen in normal mode.  In normal mode, typing ":10 " + enter takes you to the tenth line in the document.  In Execute Mode, ":10" + enter displays the tenth line just below your cursor.  Hitting return again shows the eleventh line, and so on.  You are not editing the document in this mode, simply accessing it.  Interesting, but not yet terribly useful.  Let's see what else you can do.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;:w filename&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This writes the file, just as it would if you had typed :w filename in normal mode, except again, instead of returning you to editing the document, you remain in Execute mode, meaning that the ":" appears again, awaiting your next command.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm afraid I can't imagine too many good reasons to use Execute Mode.  The best use-case I can find is that you could use the :n, where n is a line number, feature view a section of the document you are not working on without leaving the section you are working on.  If you have any tips on how Execute Mode makes your life easier, please leave a comment.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-5512836451579657392?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/5512836451579657392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=5512836451579657392' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5512836451579657392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5512836451579657392'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/08/vim-execute-mode.html' title='Vim Execute Mode'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-7254821115842162644</id><published>2011-08-08T08:41:00.000-07:00</published><updated>2011-08-08T09:03:52.460-07:00</updated><title type='text'>Safari URL opens new window</title><content type='html'>Here's a strange quirk I encountered while working with Safari mobile: HTML anchors (&amp;lt;a href="http://www.blogger.com/something.html"&amp;gt;click&amp;lt;/a&amp;gt;)  open a new Safari browser instance---every time.&lt;br /&gt;&lt;br /&gt;Now that can't be right.  As it turns out, this is indeed the standard behavior when the target attribute is not explicitly set in the anchor. Apple does provide a work around setting:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.naquah.net/blog/dennis/2008/03/21/how-to-enable-single-window-mode-in-safari"&gt;http://www.naquah.net/blog/dennis/2008/03/21/how-to-enable-single-window-mode-in-safari&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are many instances when web designers don't need targets, and they are omitted. For most browsers, when the target is not explicitly set, the browser default behavior is _self.  See the table from w3cschool:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.w3schools.com/tags/att_a_target.asp"&gt;http://www.w3schools.com/tags/att_a_target.asp&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;span class="Apple-style-span" style="font-family: verdana, helvetica, arial, sans-serif; font-size: 19px; "&gt;Attribute Values&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; "&gt;&lt;table class="reference" cellspacing="0" cellpadding="0" border="1" width="100%" style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); border-collapse: collapse; "&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th align="left" width="20%" style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; background-color: rgb(229, 238, 204); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;Value&lt;/th&gt;&lt;th align="left" width="80%" style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; background-color: rgb(229, 238, 204); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;_blank&lt;/td&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;Open the linked document in a new window or tab&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;_self&lt;/td&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;Open the linked document in the same frame as it was clicked (this is default)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;_parent&lt;/td&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;Open the linked document in the parent frameset&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;_top&lt;/td&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;Open the linked document in the full body of the window&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;&lt;i&gt;framename&lt;/i&gt;&lt;/td&gt;&lt;td style="font-family: verdana, helvetica, arial, sans-serif; font-size: 12px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(195, 195, 195); border-right-color: rgb(195, 195, 195); border-bottom-color: rgb(195, 195, 195); border-left-color: rgb(195, 195, 195); padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; vertical-align: top; "&gt;Open the linked document in a named frame&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The kicker is that Safari uses _blank as the default instead of self.  The solution for web designers?  Explicitly set the target attribute to _self for every anchor.  A bit of a hassle, but the best way to ensure that a new window does not open up with each hyperlink click.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-7254821115842162644?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/7254821115842162644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=7254821115842162644' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7254821115842162644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7254821115842162644'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/08/safari-url-opens-new-window.html' title='Safari URL opens new window'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-9040276226136631950</id><published>2011-07-13T07:30:00.000-07:00</published><updated>2011-07-13T07:33:15.716-07:00</updated><title type='text'>Huge gvim annoyance</title><content type='html'>Since upgrading to Ubuntu 11.01, when I open a document using gvim, I get a very unresponsive file browser window.  In the past, I would double click a folder and it would quickly open.  Using gvim, when I double-click, I get a wait cursor.  I often have to click four or five times before the folder opens.  Very irritating.  Anyone else have this problem? &lt;br /&gt;&lt;br /&gt;Same thing happens whether using vim-gnome or vim-gtk package.&lt;br /&gt;&lt;br /&gt;Other programs do not share this quirk.  For example, the text editor program behaves as expected when opening the files.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-9040276226136631950?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/9040276226136631950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=9040276226136631950' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/9040276226136631950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/9040276226136631950'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/07/huge-gvim-annoyance.html' title='Huge gvim annoyance'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1472687888452596009</id><published>2011-05-24T07:50:00.000-07:00</published><updated>2011-05-25T08:32:37.694-07:00</updated><title type='text'>Can't ignore IE</title><content type='html'>I've been using Ubuntu as my operating system for the past five years.  So long that I almost forgot that you must always check your web site for IE compliance.  Well, I didn't forget so much as I wasn't concerned.&lt;br /&gt;&lt;br /&gt;So since I've been shopping for contracts---I decided to return to consulting if I can line up the right opportunities--I thought it would be wise to review the user experience of my site, devinvenable.com, using IE.  I fired up a virtual machine running Windows XP, opened up IE 8, and was hit with Javascript errors.  Doh!  &lt;br /&gt;&lt;br /&gt;It's simple enough to conditionally remove code from your page that won't run on IE, or conditionally include code that does.  Even if you use cross-platform javascript libraries like jQuery, as I do, you are still bound to run into issues from time to time.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;!--[if IE]&amp;gt;&lt;br /&gt;   You are using IE (IE5+ and above), so include include script that is specific for IE here.&lt;br /&gt;&amp;lt;![endif]--&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;![if !IE]&amp;gt;&lt;br /&gt;   You are NOT using IE, so feel free to use HTML 5 features.&lt;br /&gt;&amp;lt;![endif]&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So don't get lazy and assume that IE is history.  While it's true that many savvy technical users have ditched IE for Chrome or Firefox, there are always users who will use IE because it is installed by default on their Windows OS.&lt;br /&gt;&lt;br /&gt;Writing this entry made me curious about the current browser usage statistics.  Amazingly, Firefox is way out in front with 42.9% this month, followed by Chrome at 25.6%.  Microsoft's IE is still hanging in there with a respectable 24.3%.  Still a contender but far from being the market leader in 2011.&lt;br /&gt;&lt;br /&gt;http://www.w3schools.com/browsers/browsers_stats.asp&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1472687888452596009?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1472687888452596009/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1472687888452596009' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1472687888452596009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1472687888452596009'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/05/cant-ignore-ie.html' title='Can&apos;t ignore IE'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-3440248145510819769</id><published>2011-05-20T07:36:00.000-07:00</published><updated>2011-05-22T13:34:13.543-07:00</updated><title type='text'>Job search fun!</title><content type='html'>I've decided to make a transition.  New opportunity, here I come!&lt;br /&gt;&lt;br /&gt;Looking for a new gig is always a lot of hard work.  One must find the right fit: good people, exciting technology, and room for growth.  I've talked to one prospective employer already and was asked, "What would be your ideal job if you could have anything you dream of, the perfect environment?"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It's a tough question. As a technologist, I'm probably at the top of my game.  With 14 years of software development, I've dappled in just about everything.  I don't encounter new technologies or languages often for which I've not already built products.  Because of this, I tend to stay in the trenches---doing hands on technical work.  &lt;br /&gt;&lt;br /&gt;I'm 42.  At my age, some get out of the trenches and into management.  I'm afraid I would be bored silly if my primary work tool was Microsoft Project.  That said, I am a people person, and often find myself wishing for more socialization when working with other developers, as so often they are introverts. &lt;br /&gt;&lt;br /&gt;I like building new products versus extending the work others did before me.  Who wouldn't?  So often you inherit a bug infested mess.  Building systems from scratch is fun for me.&lt;br /&gt;&lt;br /&gt;I love brainstorming and sharing ideas.  I'm a dreamer and I always have been, and this tends to work for me in the creativity department.  &lt;br /&gt;&lt;br /&gt;I love open source projects and all things Linux.  This doesn't always work to my benefit in the Tulsa market where many mid-sized corporations go with Microsoft solutions.  Perhaps I ought to go after these markets, selling CTO's on the joy of open source and living in a license free world.  For a fraction of what companies pay for licensing fees I could switch them over to free solutions.  That's a gift that would keep on giving.  Many mid-sized corporations would be well served ditching Oracle, for example, as the scalability and reliability of open source alternatives is easily demonstrable.  And what about the hundreds of thousands they spend on DBA's?  Database administration doesn't have to be this hard, folks.  &lt;br /&gt;&lt;br /&gt;I'm no closer now than when I started writing this blog entry to knowing what my ideal job would be.  But at least the creative juices are flowing.  :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-3440248145510819769?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/3440248145510819769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=3440248145510819769' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3440248145510819769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3440248145510819769'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/05/job-search-fun.html' title='Job search fun!'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1439445130827720213</id><published>2011-04-26T13:12:00.000-07:00</published><updated>2011-04-26T13:36:47.786-07:00</updated><title type='text'>Adding information to Django's default error page</title><content type='html'>Django's default error page is a handy way find out what went wrong when your view code runs into an exception that is not explicitly handled.  But sometimes you don't get the info you really want to see. For instance, today I kept running into sql errors, something I don't see too much of using Django because they are normally abstracted away by the model framework.  &lt;br /&gt;&lt;br /&gt;In my case I needed to resort to using raw sql.  The query was complex and the variables many, and thus I encountered a number of different database (cx_oracle) errors while working on the view and I didn't have a quick and dirty way to see the sql that was generated.  &lt;br /&gt;&lt;br /&gt;Getting the most recently generated sql is possible by importing django.db.connections. You can then tack it into your exception and see it on the default error page using the following technique.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;try:&lt;br /&gt;&lt;br /&gt;    """&lt;br /&gt;    This is where you build your view.  Do whatever you need to do.  In my case&lt;br /&gt;    I was inserting a row into the database here.&lt;br /&gt;    """&lt;br /&gt;except Exception as inst:&lt;br /&gt;    &lt;br /&gt;    """&lt;br /&gt;    inst.args is a tuple of arguments that were passed when the exception&lt;br /&gt;    was raised.  Django will turn this variable into the main error message&lt;br /&gt;    you see atop the default error page.  It's a tuple, so you can't append&lt;br /&gt;    to it, but you can replace it with another tuple and add any information&lt;br /&gt;    that would serve you well.&lt;br /&gt;    """&lt;br /&gt;&lt;br /&gt;    inst.args = ("%s sql:%s" % (inst.args[0], " ".join(connections[db].queries.pop()['sql'].split())),)&lt;br /&gt;&lt;br /&gt;    """&lt;br /&gt;    Sure that's ugly, but it served my debugging purpose.  Use pop to get the most &lt;br /&gt;    recent query from the queries list.  I wanted to get rid of the while space and&lt;br /&gt;    newline characters, which is the reason for the split and join.  Now you just &lt;br /&gt;    raise the exception.&lt;br /&gt;    """&lt;br /&gt;    raise&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you are going to do this kind of thing frequently you should probably explore the process-exception middleware API.  &lt;br /&gt;&lt;br /&gt;http://docs.djangoproject.com/en/dev/topics/http/middleware/?from=olddocs#process-exception&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1439445130827720213?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1439445130827720213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1439445130827720213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1439445130827720213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1439445130827720213'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/04/adding-information-to-djangos-default.html' title='Adding information to Django&apos;s default error page'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1418507891938590370</id><published>2011-04-25T11:34:00.000-07:00</published><updated>2011-04-25T11:38:15.602-07:00</updated><title type='text'>Best Django debugging technique ever</title><content type='html'>Start up your test app using the Development Server.  Then inject the following into your code where you want to examine everything, perhaps in an exception handler.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import pdb&lt;br /&gt;pdb.set_trace&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now when you hit the exception, pdb will take over the console window you started the test app.  Type help if you are unfamiliar with pdb.  All of your variables are available for review!  &lt;br /&gt;&lt;br /&gt;Sweet!  I can't believe I didn't know about this technique before.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1418507891938590370?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1418507891938590370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1418507891938590370' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1418507891938590370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1418507891938590370'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/04/best-django-debugging-technique-ever.html' title='Best Django debugging technique ever'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-3039895579764133364</id><published>2011-03-28T11:49:00.000-07:00</published><updated>2011-03-28T12:13:02.092-07:00</updated><title type='text'>Dansguardian and Youtube on Ubuntu 10.10</title><content type='html'>If you want content filtering for your kids on Ubuntu 10.10, Dansguardian does the trick, but be prepared to do some tweaking.&lt;br /&gt;&lt;br /&gt;Installation is not difficult.  Follow this recipe:&lt;br /&gt;&lt;br /&gt;https://help.ubuntu.com/community/Servers/DansGuardian&lt;br /&gt;&lt;br /&gt;My kids love youtube but the default configuration renders it useless.  Locate the configuration files in /etc/dansguardian.  You'll primarily be interested in the content under the "lists" directory.&lt;br /&gt;&lt;br /&gt;I added the following file extensions to exceptionextensionlist:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;.js&lt;br /&gt;.flv&lt;br /&gt;.mp3&lt;br /&gt;.ico&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;From bannedregexpurllist, I removed the keyword "naked", which seemed a bit over the top to me.&lt;br /&gt;&lt;br /&gt;For video playback, add this line to exceptionurllist:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;youtube.com/videoplayback&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In exceptionsitelist, add the following.  What the heck is ytimg.com?  Well apparently it serves the main static css off youtube.  I don't know if this changes and if it does how often, but I do know that the addition of this line alone had the most positive change on the overall youtube experience under Dansguardian.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ytimg.com&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Similar steps may need to be repeated for other sites that fail to render properly.  Watch the log at /var/log/dansguardian/access.log to see what's getting blocked, as that will provide the clues as to what you need to make exception for.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-3039895579764133364?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/3039895579764133364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=3039895579764133364' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3039895579764133364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3039895579764133364'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/03/dansguardian-and-ubuntu-1010.html' title='Dansguardian and Youtube on Ubuntu 10.10'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-7521116022679295244</id><published>2011-03-17T12:41:00.000-07:00</published><updated>2011-03-17T12:50:05.018-07:00</updated><title type='text'>Color highlight columns in Vim</title><content type='html'>Vim 7.3 has a new, useful feature that allows you to highlight (set the background color) of one or more columns of the document you are working on.  This comes in handy if you are working with a file that uses a fixed width format.  For example, if you want to quickly see the 44th column for every row as you scan through a file, this might assist in the task.&lt;br /&gt;&lt;br /&gt;Vim 7.3 is not yet in the Ubuntu repositories officially, but a PPM is available here:&lt;br /&gt;&lt;br /&gt;http://askubuntu.com/questions/7283/where-can-i-find-vim-7-3&lt;br /&gt;&lt;br /&gt;Once installed, use vim help to get details about colorcolumn.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;:help colorcolumn&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will show you:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;'colorcolumn' 'cc'      string  (default "")&lt;br /&gt;                        local to window&lt;br /&gt;                        {not in Vi}&lt;br /&gt;                        {not available when compiled without the |+syntax|&lt;br /&gt;                        feature}&lt;br /&gt;        'colorcolumn' is a comma separated list of screen columns that are&lt;br /&gt;        highlighted with ColorColumn |hl-ColorColumn|.  Useful to align&lt;br /&gt;        text.  Will make screen redrawing slower.&lt;br /&gt;        The screen column can be an absolute number, or a number preceded with&lt;br /&gt;        '+' or '-', which is added to or subtracted from 'textwidth'. &lt;br /&gt;&lt;br /&gt;                :set cc=+1  " highlight column after 'textwidth'&lt;br /&gt;                :set cc=+1,+2,+3  " highlight three columns after 'textwidth'&lt;br /&gt;                :hi ColorColumn ctermbg=lightgrey guibg=lightgrey&lt;br /&gt;&lt;br /&gt;        When 'textwidth' is zero then the items with '-' and '+' are not used.&lt;br /&gt;        A maximum of 256 columns are highlighted.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In practice you only need to :set cc=n, as there are default colors.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-7521116022679295244?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/7521116022679295244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=7521116022679295244' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7521116022679295244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7521116022679295244'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/03/color-highlight-columns-in-vim.html' title='Color highlight columns in Vim'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4757564455263711844</id><published>2011-03-03T10:56:00.000-08:00</published><updated>2011-03-03T10:59:56.184-08:00</updated><title type='text'>History in Python shell</title><content type='html'>I never could get used to ipython, but still wish for command history in my shell.  You too?  I'm reposting this solution here that not only saves your command history between sessions but also gives you auto-completion.&lt;br /&gt;&lt;br /&gt;Here's what you do. Store the following file in ~/.pystartup  &lt;br /&gt;&lt;br /&gt;Don't forget to export PYTHONSTARTUP as noted in the comments.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# Add auto-completion and a stored history file of commands to your Python&lt;br /&gt;# interactive interpreter. Requires Python 2.0+, readline. Autocomplete is&lt;br /&gt;# bound to the Esc key by default (you can change it - see readline docs).&lt;br /&gt;#&lt;br /&gt;# Store the file in ~/.pystartup, and set an environment variable to point&lt;br /&gt;# to it:  "export PYTHONSTARTUP=/home/user/.pystartup" in bash.&lt;br /&gt;#&lt;br /&gt;# Note that PYTHONSTARTUP does *not* expand "~", so you have to put in the&lt;br /&gt;# full path to your home directory.&lt;br /&gt;&lt;br /&gt;import atexit&lt;br /&gt;import os&lt;br /&gt;import readline&lt;br /&gt;import rlcompleter&lt;br /&gt;&lt;br /&gt;readline.parse_and_bind('tab: complete')&lt;br /&gt;historyPath = os.path.expanduser("~/.pyhistory")&lt;br /&gt;&lt;br /&gt;def save_history(historyPath=historyPath):&lt;br /&gt;    import readline&lt;br /&gt;    readline.write_history_file(historyPath)&lt;br /&gt;&lt;br /&gt;if os.path.exists(historyPath):&lt;br /&gt;    readline.read_history_file(historyPath)&lt;br /&gt;&lt;br /&gt;atexit.register(save_history)&lt;br /&gt;del os, atexit, readline, rlcompleter, save_history, historyPath&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Please note that this will only work on *nix systems. As readline is only available in Unix platform.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4757564455263711844?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4757564455263711844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4757564455263711844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4757564455263711844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4757564455263711844'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2011/03/history-in-python-shell.html' title='History in Python shell'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-3910839565633432308</id><published>2010-11-24T07:28:00.000-08:00</published><updated>2010-11-24T07:31:05.950-08:00</updated><title type='text'>Thank God for Tripper McCarthy</title><content type='html'>A long time ago, in our galaxy, Tripper McCarthy posted this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tripper McCarthy &lt;Trip...@pdsi-software.com&gt; Tue Jun 24 2003 19:19:31 GMT-0500 (CDT) &lt;br /&gt;&lt;br /&gt; There have been several posts asking how to change the body of a message&lt;br /&gt;(not the header) from within a handler. Here is a way to pull it off. It's a&lt;br /&gt;little strange, but it works. &lt;br /&gt;&lt;br /&gt;    public void invoke(MessageContext msgContext) throws AxisFault {&lt;br /&gt;        try {&lt;br /&gt;            javax.xml.soap.SOAPMessage soapMessage =&lt;br /&gt;msgContext.getRequestMessage();&lt;br /&gt;            String oldRequest =&lt;br /&gt;soapMessage.getSOAPPart().getEnvelope().toString();&lt;br /&gt;            &lt;br /&gt;            int index = oldRequest.indexOf("&lt;processAttributesParam");&lt;br /&gt;            index = oldRequest.indexOf("&gt;",index);&lt;br /&gt;            String newRequest = oldRequest.substring(0,index+1) +&lt;br /&gt;                "&lt;test_element&gt;5&lt;/test_element&gt;" +&lt;br /&gt;                oldRequest.substring(index+1,oldRequest.length());&lt;br /&gt;            &lt;br /&gt;            ByteArrayInputStream istream = new&lt;br /&gt;ByteArrayInputStream(newRequest.getBytes());            &lt;br /&gt;            Message msg = new Message(istream, false);&lt;br /&gt;            msgContext.setRequestMessage(msg);&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;        catch(Exception e) {&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;            throw new AxisFault(e.getMessage());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Thanks Tripper.  I've been beating my head for hours trying to modify the message using the deeply-nested object model in Handler.  Your solution cut to the chase.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-3910839565633432308?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/3910839565633432308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=3910839565633432308' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3910839565633432308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3910839565633432308'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/11/thank-god-for-tripper-mccarthy.html' title='Thank God for Tripper McCarthy'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4611171878016837757</id><published>2010-10-22T11:01:00.000-07:00</published><updated>2010-10-25T09:13:44.305-07:00</updated><title type='text'>RedHat Enterprise 5 and Python</title><content type='html'>Update:&lt;br /&gt;&lt;br /&gt;I found it difficult to make Python 2.6 the default distribution for RHEL.  It jacks up YUM when you do it.  So I'm abandoning that approach altogether.  The following notes were taken before I decided to take a different approach.  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Python 2.4 is the python that ships with RedHat Enterprise Linux 5.  This will never do.  &lt;br /&gt;&lt;br /&gt;I didn't remove 2.4 because some suggested against it, saying that RedHat needs to keep this version around.  &lt;br /&gt;&lt;br /&gt;Suppose you want to go to version 2.6.  Here's what to do: either install from repo (yum install python26), which requires that you enable EPEL, or build from Python from source.  It will install along side 2.4.  When you next run Python you will find that the OS is still defaulting to 2.4.  To fix this run update-alternatives.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;update-alternatives --config python&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Run Python again and your system wide default should now be the latest version you installed.&lt;br /&gt;&lt;br /&gt;Alert:  After building my own 2.6 and following the process above, I discovered that I had inadvertently screwed up YUM.  Beware this process until I post final comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4611171878016837757?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4611171878016837757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4611171878016837757' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4611171878016837757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4611171878016837757'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/10/redhat-enterprise-5-and-python.html' title='RedHat Enterprise 5 and Python'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-2271036044249540853</id><published>2010-10-22T10:59:00.001-07:00</published><updated>2010-10-22T10:59:42.209-07:00</updated><title type='text'>Shrink PDF file on linux (command line)</title><content type='html'>gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET -sPAPERSIZE=a4 -dBATCH -sOutputFile=output.pdf input.pdf&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-2271036044249540853?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/2271036044249540853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=2271036044249540853' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2271036044249540853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2271036044249540853'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/10/shrink-pdf-file-on-linux-command-line.html' title='Shrink PDF file on linux (command line)'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-2799103259828126985</id><published>2010-10-14T17:15:00.000-07:00</published><updated>2010-10-14T17:28:25.890-07:00</updated><title type='text'>Convert 32 to 16 bit WAV (Linux) recipe</title><content type='html'>Check file info:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;devin@studio:~/Music/samples$ sndinfo funky.wav &lt;br /&gt;virtual_keyboard real time MIDI plugin for Csound&lt;br /&gt;PortMIDI real time MIDI plugin for Csound&lt;br /&gt;PortAudio real-time audio module for Csound&lt;br /&gt;util sndinfo:&lt;br /&gt;funky.wav:&lt;br /&gt; srate 44100, stereo, 32 bit WAV, 9.835 seconds&lt;br /&gt; (433737 sample frames)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Convert to 16 bit:&lt;br /&gt;&lt;br /&gt;  sox  funky.wav -b 16 funky16.wav&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-2799103259828126985?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/2799103259828126985/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=2799103259828126985' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2799103259828126985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2799103259828126985'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/10/convert-32-to-16-bit-wav-linux-recipe.html' title='Convert 32 to 16 bit WAV (Linux) recipe'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6937925585236355378</id><published>2010-09-09T09:23:00.000-07:00</published><updated>2010-09-09T09:44:34.593-07:00</updated><title type='text'>cx_Oracle and out cursor</title><content type='html'>If you need to call an Oracle stored procedure using cx_Oracle, and one of the arguments is an "out" cursor, this is how it is done.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;connection = cx_Oracle.connect(connstr)&lt;br /&gt;cursor = connection.cursor()&lt;br /&gt;out = cursor.var(cx_Oracle.CURSOR)&lt;br /&gt;&lt;br /&gt;items = cursor.callproc('EXAMPLE_PKG.get_some_data',&lt;br /&gt;                ['02-SEP-2010',&lt;br /&gt;                '03-SEP-2010',&lt;br /&gt;                332123.0,&lt;br /&gt;                896798.0,&lt;br /&gt;                68567.0,&lt;br /&gt;                'xyz',&lt;br /&gt;                out&lt;br /&gt;                ]&lt;br /&gt;&lt;br /&gt;print items[6].fetchall()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A list of objects will be returned from callproc containing each of the arguments passed in.  If any of the arguments passed are "out" arguments, they will have been modified to hold the results.  In my case the seventh argument (items[6] --- zero indexed) returned a cursor.  This cursor is then used to retrieve the result set.  &lt;br /&gt;&lt;br /&gt;I had trouble finding a good example of this usage pattern for cx_Oracle on the net, so here's one for the next lucky guy or girl who is digging for this answer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6937925585236355378?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6937925585236355378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6937925585236355378' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6937925585236355378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6937925585236355378'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/09/cxoracle-and-out-cursor.html' title='cx_Oracle and out cursor'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-8222756479919894434</id><published>2010-07-30T11:48:00.000-07:00</published><updated>2011-05-22T13:33:49.619-07:00</updated><title type='text'>OpenGL Intellivision Man</title><content type='html'>Not long ago I set out to turn an animated gif I found of the Intellivision Running Man into an OpenGL generated video clip.  My goal was to shrink the images into tiny bitmaps, a.k.a. 8-bit, and then use the resulting bitmap data as positioning information within a 3D space.  Another way of saying it: I wanted to render each pixel from the original images as a 3D block.  Jump to the video to get a better idea about what I mean:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=E1rXt0l2pxY"&gt;http://www.youtube.com/watch?v=E1rXt0l2pxY&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Along the way I took a few turns.  I never did reduce the image data to its smallest possible representation.  I did reduce the image size for each image to 24x24 pixels and I converted the image data to grayscale.  Using the handy PIL library, I was able to pull in the bitmap file data as a tuple of pixel values.  I used each "pixel" to offset the drawing position in pyglet's on_draw handler.  &lt;br /&gt;&lt;br /&gt;The code I used to render the animation is a hack of an example found here:&lt;br /&gt;&lt;br /&gt;http://code.google.com/p/pyglet-hene/source/browse/trunk/&lt;br /&gt;&lt;br /&gt;This is a fairly ugly hack, meaning I didn't work to make the code beautiful.  It's just the original code, chopped, altered and enhanced as needed to accomplish what I wanted to see rendered on the screen.  &lt;br /&gt;&lt;br /&gt;Though not provided here, to run this code an image directory needs to be provided named "data" containing a series of bitmaps.  My directory contains this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ls -ltr&lt;br /&gt;total 32&lt;br /&gt;-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 9.bmp&lt;br /&gt;-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 8.bmp&lt;br /&gt;-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 6.bmp&lt;br /&gt;-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 5.bmp&lt;br /&gt;-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 4.bmp&lt;br /&gt;-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 3.bmp&lt;br /&gt;-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 2.bmp&lt;br /&gt;-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 1.bmp&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you are so inclined to try your own little experiment, find a favorite animated gif on the web, extract each frame, reduce size, convert to grayscale and drop your own images in a directory similar to the one I created here.  Your animation result should be similar to what I've produced here.&lt;br /&gt;&lt;br /&gt;And here's the complete source:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from pyglet.gl import *&lt;br /&gt;import pyglet&lt;br /&gt;from pyglet.window import *&lt;br /&gt;from pyglet import image&lt;br /&gt;import os&lt;br /&gt;from PIL import Image&lt;br /&gt;import glob&lt;br /&gt;from math import sin, cos&lt;br /&gt;&lt;br /&gt;window = pyglet.window.Window(width=640, height=480, resizable=True)&lt;br /&gt;&lt;br /&gt;y=0.0&lt;br /&gt;x=-10.0     &lt;br /&gt;z=10.0    &lt;br /&gt;xspeed = 0.5&lt;br /&gt;yspeed = 0.0&lt;br /&gt;lx=ly=0&lt;br /&gt;lz=-2&lt;br /&gt;angle=ratio=0.0&lt;br /&gt;&lt;br /&gt;boxcol = [ [1.0, 0.0, 0.0], # bright: red&lt;br /&gt;           [1.0, 0.5, 0.0],        # orange&lt;br /&gt;           [1.0, 1.0, 0.0],        # yellow&lt;br /&gt;           [0.0, 1.0, 0.0],        # green&lt;br /&gt;           [0.0, 1.0, 1.0],        # blue&lt;br /&gt;                        ]&lt;br /&gt;&lt;br /&gt;# Dark: red, orange, yellow, green ,blue&lt;br /&gt;topcol =[ [0.6, 0.0, 0.0],&lt;br /&gt;          [0.6, 0.25, 0.0],&lt;br /&gt;          [0.6, 0.6, 0.0],&lt;br /&gt;          [0.0, 0.6 ,0.0],&lt;br /&gt;          [0.0, 0.6, 0.6]]&lt;br /&gt;                        &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;box = None # display list storage&lt;br /&gt;top = None #display list storage&lt;br /&gt;&lt;br /&gt;yloop = None # loop for y axis&lt;br /&gt;xloop = None # loop for x axies&lt;br /&gt;&lt;br /&gt;bmpdata = None &lt;br /&gt;nextimg = 0&lt;br /&gt;files = None&lt;br /&gt;&lt;br /&gt;def load_image_data():&lt;br /&gt;    global bmpdata, bmpdatalen, files &lt;br /&gt;&lt;br /&gt;    files = glob.glob('data/*.bmp')&lt;br /&gt;    files.sort()&lt;br /&gt;    bmpdata = map(lambda x: Image.open(x).getdata(), files.__iter__())&lt;br /&gt;    bmpdatalen = len(bmpdata)&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;def build_lists():&lt;br /&gt;  global box, top&lt;br /&gt;  box = glGenLists(2)&lt;br /&gt;&lt;br /&gt;  glNewList(box, GL_COMPILE)    # new compiled box display list&lt;br /&gt;&lt;br /&gt;  # draw the box without the top (it will be store in display list&lt;br /&gt;  # and will not appear on the screen)&lt;br /&gt;  glBegin(GL_QUADS)&lt;br /&gt;  &lt;br /&gt;  # front face&lt;br /&gt;  glTexCoord2f(0.0, 0.0);       glVertex3f(-1.0, -1.0, 1.0)&lt;br /&gt;  glTexCoord2f(1.0, 0.0);       glVertex3f(1.0, -1.0, 1.0)&lt;br /&gt;  glTexCoord2f(1.0, 1.0);       glVertex3f(1.0, 1.0, 1.0)&lt;br /&gt;  glTexCoord2f(0.0, 1.0);       glVertex3f(-1.0, 1.0, 1.0)&lt;br /&gt;  # back face&lt;br /&gt;  glTexCoord2f(1.0, 0.0);       glVertex3f(-1.0, -1.0, -1.0)&lt;br /&gt;  glTexCoord2f(1.0, 1.0);       glVertex3f(-1.0, 1.0, -1.0)&lt;br /&gt;  glTexCoord2f(0.0, 1.0);       glVertex3f(1.0, 1.0, -1.0)&lt;br /&gt;  glTexCoord2f(0.0, 0.0);       glVertex3f(1.0, -1.0, -1.0)&lt;br /&gt;  # right face&lt;br /&gt;  glTexCoord2f(1.0, 0.0);       glVertex3f(1.0, -1.0, -1.0)&lt;br /&gt;  glTexCoord2f(1.0, 1.0);       glVertex3f(1.0, 1.0, -1.0)&lt;br /&gt;  glTexCoord2f(0.0, 1.0);       glVertex3f(1.0, 1.0, 1.0)&lt;br /&gt;  glTexCoord2f(0.0, 0.0);       glVertex3f(1.0, -1.0, 1.0)&lt;br /&gt;  # left face&lt;br /&gt;  glTexCoord2f(0.0, 0.0);       glVertex3f(-1.0, -1.0, -1.0)&lt;br /&gt;  glTexCoord2f(1.0, 0.0);       glVertex3f(-1.0, -1.0, 1.0)&lt;br /&gt;  glTexCoord2f(1.0, 1.0);       glVertex3f(-1.0, 1.0, 1.0)&lt;br /&gt;  glTexCoord2f(0.0, 1.0);       glVertex3f(-1.0, 1.0, -1.0)&lt;br /&gt;  glEnd()&lt;br /&gt;&lt;br /&gt;  glEndList()   # Done building the list&lt;br /&gt;&lt;br /&gt;  top=box+1&lt;br /&gt;&lt;br /&gt;  glNewList(top, GL_COMPILE)    # new compiled top display list&lt;br /&gt;  # Top face&lt;br /&gt;  glBegin(GL_QUADS)&lt;br /&gt;  glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0)&lt;br /&gt;  glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 1.0)&lt;br /&gt;  glTexCoord2f(1.0, 0.0); glVertex3f(1.0, 1.0, 1.0)&lt;br /&gt;  glTexCoord2f(1.0, 1.0); glVertex3f(1.0, 1.0, -1.0)&lt;br /&gt;  &lt;br /&gt;  glTexCoord2f(1.0, 1.0);       glVertex3f(-1.0, -1.0, -1.0)&lt;br /&gt;  glTexCoord2f(0.0, 1.0);       glVertex3f(1.0, -1.0, -1.0)&lt;br /&gt;  glTexCoord2f(0.0, 0.0);       glVertex3f(1.0, -1.0, 1.0)&lt;br /&gt;  glTexCoord2f(1.0, 0.0);       glVertex3f(-1.0, -1.0, 1.0)&lt;br /&gt;  glEnd()&lt;br /&gt;  glEndList()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;     &lt;br /&gt;def load_gl_textures():&lt;br /&gt;        # load bitmaps and convert to textures&lt;br /&gt;        global texture, texture_file, texture_surf&lt;br /&gt;        #texture_file = os.path.join('data', 'cube.bmp')&lt;br /&gt;        texture_file = files[nextimg]&lt;br /&gt;        texture_surf = image.load(texture_file)&lt;br /&gt;        texture = texture_surf.get_texture()&lt;br /&gt;        glBindTexture(GL_TEXTURE_2D, texture.id)&lt;br /&gt;&lt;br /&gt;        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)&lt;br /&gt;        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        &lt;br /&gt;def init():&lt;br /&gt;    """&lt;br /&gt;    Pyglet oftentimes calls this setup()    &lt;br /&gt;    """&lt;br /&gt;    glEnable(GL_TEXTURE_2D)&lt;br /&gt;&lt;br /&gt;    load_image_data()&lt;br /&gt;    load_gl_textures()&lt;br /&gt;    build_lists()&lt;br /&gt;&lt;br /&gt;    glShadeModel(GL_SMOOTH) # Enables smooth shading&lt;br /&gt;    glClearColor(0.0, 0.0, 0.0, 0.0) #Black background&lt;br /&gt;    &lt;br /&gt;    glClearDepth(1.0)               # Depth buffer setup&lt;br /&gt;    glEnable(GL_DEPTH_TEST)         # Enables depth testing&lt;br /&gt;    glDepthFunc(GL_LEQUAL)          # The type of depth test to do&lt;br /&gt;&lt;br /&gt;    glEnable(GL_LIGHT0) # quick and dirty lighting &lt;br /&gt;    &lt;br /&gt;    #glEnable(GL_LIGHTING)  # enable lighting&lt;br /&gt;    glEnable(GL_COLOR_MATERIAL)     # enable coloring&lt;br /&gt;&lt;br /&gt;    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)       # Really nice perspective calculations&lt;br /&gt;       &lt;br /&gt;    &lt;br /&gt;     &lt;br /&gt;@window.event&lt;br /&gt;def on_draw():&lt;br /&gt;    global nextimg, bmpdata, x, y, z, lx, ly, lz&lt;br /&gt;&lt;br /&gt;    # Here we do all the drawing&lt;br /&gt;    glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT)&lt;br /&gt;&lt;br /&gt;    # Select the texture&lt;br /&gt;    load_gl_textures()&lt;br /&gt;    #glBindTexture(GL_TEXTURE_2D, texture.id)&lt;br /&gt;&lt;br /&gt;    xloop = 1&lt;br /&gt;    yloop = 1&lt;br /&gt;    &lt;br /&gt;    mandata = bmpdata[nextimg]&lt;br /&gt;    for idx in range (0, len(mandata)):&lt;br /&gt;        if (idx+1) % 24 == 0:&lt;br /&gt;            yloop += 1&lt;br /&gt;            xloop = 1&lt;br /&gt;        else:&lt;br /&gt;            xloop += 1&lt;br /&gt;        if mandata[idx] &lt; 100:&lt;br /&gt;&lt;br /&gt;            glLoadIdentity()        # reset our view&lt;br /&gt;            gluLookAt(x,y,z, x+lx , y+ly, z+lz, 0.0, 1.0, 0.0)&lt;br /&gt;&lt;br /&gt;            glTranslatef( xloop*1.8 - 30 ,&lt;br /&gt;                                      28 - yloop*2.4 ,&lt;br /&gt;                                      -60.0)&lt;br /&gt;            glColor3f(*boxcol[xloop % 4]) # select a box color&lt;br /&gt;            glCallList(box) # draw the box&lt;br /&gt;&lt;br /&gt;            glColor3f(*topcol[1])&lt;br /&gt;            glCallList(top)  # draw the top&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    return pyglet.event.EVENT_HANDLED&lt;br /&gt;      &lt;br /&gt;def moveMeFlat(direction):&lt;br /&gt;    global x, z, y, lx, lz, ly &lt;br /&gt;    x = x - direction*(lx)*0.75;&lt;br /&gt;    y = y + direction*(ly)*0.5;&lt;br /&gt;    z = z + direction*(lz)*0.5;&lt;br /&gt; &lt;br /&gt;def orientMe(ang):&lt;br /&gt;    global lx, lz&lt;br /&gt;    lx = sin(ang)&lt;br /&gt;    lz = -cos(ang)&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;def update(dt):&lt;br /&gt;    global z, angle&lt;br /&gt;    angle +=0.005&lt;br /&gt;    orientMe(angle)&lt;br /&gt;    moveMeFlat(0.5)&lt;br /&gt;&lt;br /&gt;def update2(dt):&lt;br /&gt;    global nextimg&lt;br /&gt;    if nextimg &lt; bmpdatalen-1:&lt;br /&gt;        nextimg += 1&lt;br /&gt;    else:&lt;br /&gt;        nextimg = 0 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;pyglet.clock.schedule_interval(update2, .1)&lt;br /&gt;pyglet.clock.schedule(update)&lt;br /&gt;        &lt;br /&gt;@window.event&lt;br /&gt;def on_resize(width, height):&lt;br /&gt;        if height==0:&lt;br /&gt;            height = 1&lt;br /&gt;        glViewport(0, 0, width, height)&lt;br /&gt;        glMatrixMode(GL_PROJECTION)&lt;br /&gt;        glLoadIdentity()&lt;br /&gt;&lt;br /&gt;        # Calculate the aspect ratio of the window&lt;br /&gt;        gluPerspective(45.0, 1.0*width/height, 0.1, 100.0)&lt;br /&gt;&lt;br /&gt;        glMatrixMode(GL_MODELVIEW)&lt;br /&gt;        glLoadIdentity()&lt;br /&gt;        return pyglet.event.EVENT_HANDLED&lt;br /&gt;        &lt;br /&gt;init()  &lt;br /&gt;&lt;br /&gt;pyglet.app.run()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-8222756479919894434?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/8222756479919894434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=8222756479919894434' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8222756479919894434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8222756479919894434'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/07/opengl-intellivision-man.html' title='OpenGL Intellivision Man'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-7819147244151068149</id><published>2010-07-20T07:16:00.000-07:00</published><updated>2010-07-20T07:31:04.675-07:00</updated><title type='text'>Cross-compile ActiveMQ-cpp on Centos 5</title><content type='html'>To date an RPM for activemq-cpp is not available for Centos 5.  I found RPMs in Fedora 13 and 14 repositories, but due to dependencies on fresher libs, they won't install.    &lt;br /&gt;&lt;br /&gt;Building for 32 bit architecture on 64 bit Centos 5 was a bit tricky.  Here's the recipe I came up with that worked for me:&lt;br /&gt;&lt;br /&gt;Install dependencies:  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;yum install expat-devel zlib-devel uuid-c++-devel openssl-devel&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Download sources from here or other mirrors:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;wget http://www.carfab.com/apachesoftware/activemq/activemq-cpp/source/activemq-cpp-library-3.2.1-src.tar.gz&lt;br /&gt;wget http://mirror.candidhosting.com/pub/apache/apr/apr-1.4.2.tar.gz&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Extract archives and build APR first.  Note PKG_CONFIG_PATH, as this is one of the keys to ensuring that lib64 libraries are not found during link step.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@myserver] cd apr-1.4.2&lt;br /&gt;[root@myserver] ./configure --prefix=/usr --libdir=/usr/lib CXXFLAGS="-m32" LDFLAGS="-m32" CFLAGS="-m32" --build=i686-redhat-linux-gnu PKG_CONFIG_PATH=/usr/lib/pkgconfig &lt;br /&gt;[root@myserver] ./make&lt;br /&gt;[root@myserver] ./make install&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next build and install ActiveMQ-cpp:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@myserver] cd ../activemq-cpp-library-3.2.1&lt;br /&gt;[root@myserver] ./configure --prefix=/usr --libdir=/usr/lib CXXFLAGS="-m32" LDFLAGS="-m32" CFLAGS="-m32" --build=i686-redhat-linux-gnu PKG_CONFIG_PATH=/usr/lib/pkgconfig --with-apr=../apr-1.4.2/apr-1-config&lt;br /&gt;[root@myserver] ./make&lt;br /&gt;[root@myserver] ./make install&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-7819147244151068149?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/7819147244151068149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=7819147244151068149' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7819147244151068149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7819147244151068149'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/07/cross-compile-activemq-cpp-on-centos-5.html' title='Cross-compile ActiveMQ-cpp on Centos 5'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-148068353075630881</id><published>2010-07-13T06:08:00.000-07:00</published><updated>2010-07-13T07:18:18.228-07:00</updated><title type='text'>qemu-img</title><content type='html'>qemu-img is a handy tool for converting one virtual machine image format into another.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;qemu-img convert windowsxp.img -O vdi windowsxp.vdi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I had need for its use after running into errors creating a virtual machine with virt-manager.  KVM managed by virt-manager has been my recent virtualization solution of choice, that is, until last Friday when I hit a snag creating a new virtual machine for WindowsXP.  The installation process got stuck and I wasn't able to recover.  Following advice from somewhere it the net-realm, I opted to create the image using this easy command line two-liner.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; dd if=/dev/zero of=vm8.img bs=2048k count=12000&lt;br /&gt; kvm -m 512 -cdrom winxp.iso -boot d v8.img&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The installation was successful and running the image from the command line using kvm was a snap, but what I really wanted was to place this image under the control of virt-manager.&lt;br /&gt;&lt;br /&gt;I couldn't find a nice option to import an existing image, so if it exists it is not very intuitive.  Apparently to place it under virt-manager's control I would need to create an xml file under /etc/libvirt/qemu/ and in addition I would probably need to convert the image from raw format to qcow2.  But after messing around with this for too long, a colleague recommended I use virtualbox.&lt;br /&gt;&lt;br /&gt;I used virtualbox in the past, so I figured a different approach might be worthwhile and  should get me beyond the headache in the short term. But what about the work I did creating the original image?  Installing WindowsXP is a hassle, not to mention the effort I'd put into installing subsequent software on the image.&lt;br /&gt;&lt;br /&gt;And that's where qemu-img came in. virtualbox only reads vmi formatted images, thus I converted my raw image to vmi.&lt;br /&gt;&lt;br /&gt;Updated: FAIL&lt;br /&gt;&lt;br /&gt;Importing the new vmi was easy enough, but once I created the new virtual machine and started it...I got this error from virtualbox-osi:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;"Failed to start the virtual machine windowsxp.  VirtualBox can't operate in VMX root mode.  Please disable the KVM kernel extension, recompile your kernel and reboot."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Okay...but I will silently resent you.&lt;br /&gt;&lt;br /&gt;Updated:  Original image hung after removing KVM.  At this point I'm going to throw up my hands and create a new image and fresh install.  I'm at the point of diminishing returns...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-148068353075630881?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/148068353075630881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=148068353075630881' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/148068353075630881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/148068353075630881'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/07/qemu-img.html' title='qemu-img'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6601108479457438249</id><published>2010-07-07T14:18:00.001-07:00</published><updated>2010-07-07T15:28:29.793-07:00</updated><title type='text'>Going really 8-bit</title><content type='html'>Back when I was a kid, my nerd friends and I would create graphics for our Commodore computers by filling filling in squares on graph paper and calculating the bitmaps. A single character on the Commodore 64 and Vic 20 was an 8x8 grid.  &lt;br /&gt;&lt;br /&gt;I recently found an 8-bit image fondly remembered from my youth, the Intellivision Running Man, in animated GIF format.  I converted the GIF to a short video, which I embedded in a &lt;a href="http://www.youtube.com/watch?v=6S1eo305mLQ"&gt;video project&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Some of my video conversion notes were covered in &lt;a href="http://devinvenable.blogspot.com/2010/06/animated-gif-to-video.html"&gt;another post&lt;/a&gt; and some are on my &lt;a href="http://wiki.devinvenable.com/mediawiki/index.php/Video"&gt;wiki&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I want to extract the Intellivision Running Man bitmaps for use in an opengl project that I'm thinking about doing.  Though it would probably be simpler for me to just sit down with pen and paper to graph and calculate the bitmaps, I'm hoping to find tools that will allow me to extract the data directly from raw video. &lt;br /&gt;&lt;br /&gt;I first needed to reduce the screen resolution as much as possible by shrinking the video and dropping frames.  Here I shrank the video output to 24x24 and reduced the frame rate to 4 frames per second.&lt;br /&gt;&lt;br /&gt; ffmpeg -i intel.avi -r 4 -s 24x24 intel8bit.avi&lt;br /&gt;&lt;br /&gt;Next I extracted individual bitmap images:&lt;br /&gt;&lt;br /&gt; ffmpeg -i intel8bit.avi -f image2 foo_%5d.bmp&lt;br /&gt;&lt;br /&gt;I initially took one image into Gimp and used Desaturate to convert it to grayscale, and then I used Levels to reduce image to pure Black or White.  But I didn't want to repeat this again and again.  So I wrote a small Python script which achieved the same goal and along the way got to play with the PIL library, which I've not used before.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from PIL import Image&lt;br /&gt;import sys, os&lt;br /&gt;&lt;br /&gt;def bw(pt):&lt;br /&gt;    if pt&gt;126:&lt;br /&gt;        return 255&lt;br /&gt;    else:&lt;br /&gt;        return 0&lt;br /&gt;&lt;br /&gt;for infile in sys.argv[1:]:&lt;br /&gt;    f, e = os.path.splitext(infile)&lt;br /&gt;    outfile = f + "_mod" + e&lt;br /&gt;&lt;br /&gt;    im = Image.open(infile)&lt;br /&gt;&lt;br /&gt;    im = im.convert('L')&lt;br /&gt;    out = im.point(bw)&lt;br /&gt;&lt;br /&gt;    out.save(outfile)&lt;br /&gt;    print outfile&lt;br /&gt;&lt;/pre&gt;  &lt;br /&gt;&lt;br /&gt;This little script loads a bitmap then uses convert() with the 'L' option to make it grayscale.  (I couldn't find a comprehensive list of options for convert---the documentation could use some work.)&lt;br /&gt;&lt;br /&gt;Finally, I used the point method that passes each pixel in the bitmap data to a custom function.  Your function can do anything, but mine just looks at the value, makes higher level grays absolute black and lower level grays absolute white.  point() returns a copy of the bitmap file (headers updated and intact) with the transformed result, which is then saved.&lt;br /&gt;&lt;br /&gt;At this point I have true black and white bitmaps.&lt;br /&gt;&lt;br /&gt;I wanted to quickly visualize my bitmap, to get a feel for how much more I want to reduce the size of my bitmaps.  This little script renders my images to screen as a series of X's.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from PIL import Image&lt;br /&gt;import sys, os&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;for infile in sys.argv[1:]:&lt;br /&gt;&lt;br /&gt;    im = Image.open(infile)&lt;br /&gt;    data = im.getdata()&lt;br /&gt;    for idx in range (0, len(data)):&lt;br /&gt;        i = data[idx]&lt;br /&gt;        if i == 255:&lt;br /&gt;            print 'X',&lt;br /&gt;        else:&lt;br /&gt;            print ' ',&lt;br /&gt;&lt;br /&gt;        if (idx+1) % 24 == 0:&lt;br /&gt;            print ''&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The output looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;devin@studio:~/src/py$ python showdata.py /home/devin/Video/bitmaps/foo_00041_mod.bmp &lt;br /&gt;&lt;br /&gt;X X X X X X X X X X X X X X X X X X X X X X X X &lt;br /&gt;X X X X X X X X X X X X X X X X X X X X X X X X &lt;br /&gt;X X X X X X X X X X X X X X X X X X X X X X X X &lt;br /&gt;X X X X X X X X X X X X       X X X X X X X X X &lt;br /&gt;X X X X X X X X X X X X     X X X X X X X X X X &lt;br /&gt;X X X X X X X X                   X X X X X X X &lt;br /&gt;X X X X X                   X X X X X X X X X X &lt;br /&gt;X X X X X                   X X X X X X X X X X &lt;br /&gt;X X X X X                   X X X X X X X X X X &lt;br /&gt;X X X X X                     X X X X X X X X X &lt;br /&gt;X X X X X X                       X X X X X X X &lt;br /&gt;X X X X X X X X         X X X X X X X X X X X X &lt;br /&gt;X X X X X X X X             X X X X X X X X X X &lt;br /&gt;X X X X X                         X X X X X X X &lt;br /&gt;X X X X X     X X X X X X X X     X X X X X X X &lt;br /&gt;X X X X X     X X X X X X X X     X X X X X X X &lt;br /&gt;X X X X X     X X X             X X X X X X X X &lt;br /&gt;X X X X X     X X X     X X X X X X X X X X X X &lt;br /&gt;X X X X X     X X X X X X X X X X X X X X X X X &lt;br /&gt;X X X X X     X X X X X X X X X X X X X X X X X &lt;br /&gt;X X X X X X X X X X X X X X X X X X X X X X X X &lt;br /&gt;X X X X X X X X X X X X X X X X X X X X X X X X &lt;br /&gt;X X X X X X X X X X X X X X X X X X X X X X X X &lt;br /&gt;X X X X X X X X X X X X X X X X X X X X X X X X&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6601108479457438249?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6601108479457438249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6601108479457438249' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6601108479457438249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6601108479457438249'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/07/going-really-8-bit.html' title='Going really 8-bit'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-2567147368963986798</id><published>2010-06-25T06:49:00.000-07:00</published><updated>2010-06-25T07:08:56.212-07:00</updated><title type='text'>Animated gif to video</title><content type='html'>This little recipe worked for the basic job of converting the giv to an avi.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mplayer animated.gif -vo yuv4mpeg&lt;br /&gt;ffmpeg -i stream.yuv -an -r 24 -b 640 -s vga -aspect 4:3 test.avi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;However I wanted to loop the gif, but ffmpeg's -loop_input and -loop_ouput had no affect.  Decided to make a copy and cat a few times...but this didn't work as expected. (Save yourself time and don't copy this section!)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mencoder -oac copy -ovc copy -forceidx test.avi test2.avi -o test.avi&lt;br /&gt;mencoder -oac copy -ovc copy -forceidx test.avi test2.avi -o test.avi&lt;br /&gt;mencoder -oac copy -ovc copy -forceidx test.avi test2.avi -o test.avi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Tried this with no luck:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; mplayer -loop 10 test.avi -vo yuv4mpeg&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally found a good way:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;avimerge -i test.avi test2.avi test3.avi - o mergedfile.avi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sweet!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-2567147368963986798?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/2567147368963986798/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=2567147368963986798' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2567147368963986798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2567147368963986798'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/06/animated-gif-to-video.html' title='Animated gif to video'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-289976215868670245</id><published>2010-06-23T04:14:00.000-07:00</published><updated>2010-06-24T18:49:21.591-07:00</updated><title type='text'>Logitech webcam issues with Ubuntu 10.04 LTS</title><content type='html'>&lt;span style="font-style:italic;"&gt;&lt;span style="font-weight:bold;"&gt;Update:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Fixed (well, a workaround): &lt;span style="font-style:italic;"&gt;Setting environment variable LD_PRELOAD prior to running video problem solves issues on my box.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;$ LD_PRELOAD=/usr/lib/libv4l/v4l1compat.so cheese&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;---Original Text follows---&lt;br /&gt;&lt;br /&gt;cheese and other video programs have been working rather poorly on my AMD64 bit Ubuntu Studio install.  &lt;br /&gt;&lt;br /&gt;Errors like the following show up:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;libv4lconvert: Error decompressing JPEG: unknown huffman code: 0000ffd9&lt;br /&gt;libv4lconvert: Error decompressing JPEG: unknown huffman code: 0000ffff&lt;br /&gt;libv4lconvert: Error decompressing JPEG: unknown huffman code: 0000ffec&lt;br /&gt;libv4lconvert: Error decompressing JPEG: unknown huffman code: 0000ffff&lt;br /&gt;libv4lconvert: Error decompressing JPEG: unknown huffman code: 0000ffd9&lt;br /&gt;libv4lconvert: Error decompressing JPEG: unknown huffman code: 0000fffd&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Rebuilding the latest drivers from linuxtv.org didn't help.  I'm still looking for a solution.&lt;br /&gt;&lt;br /&gt;Note: Same camera produces same error on a second computer running same version of Ubuntu.  &lt;br /&gt;&lt;br /&gt;lsusb&lt;br /&gt;&lt;br /&gt;Bus 005 Device 004: ID 046d:089d Logitech, Inc. QuickCam E2500 series&lt;br /&gt;&lt;br /&gt;gstreamer-properties is a great test tool for this kind of thing.  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'm going to log a bug on this one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-289976215868670245?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/289976215868670245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=289976215868670245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/289976215868670245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/289976215868670245'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/06/logitech-webcam-issues-with-ubuntu-1004.html' title='Logitech webcam issues with Ubuntu 10.04 LTS'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1534850794621682982</id><published>2010-06-20T20:13:00.000-07:00</published><updated>2010-06-20T20:22:26.472-07:00</updated><title type='text'>New RSS feed</title><content type='html'>If you are feeding this blog into Google Reader, update your settings and pull from here instead:&lt;br /&gt;&lt;br /&gt;http://www.devinvenable.com/rss/feed.xml&lt;br /&gt;&lt;br /&gt;I pull my activity from several sources (including blogger.com) to display a nicely formatted aggregate of my online activity on my home page.  But it hasn't been possible to subscribe to the aggregate until now.  I use Universal Feed Parser to combine my various feeds and had hoped that there would be a nice method to easily turn the parsed values back into serialized ATOM.  Poking around, I didn't find any such method, so I used PyRSS2Gen to pack the parsed dictionary back into RSS.  It probably would have been just as easy to load an XML library and just write out XML, but I didn't want to have to read specifications or, really, do much work on this.  Still took me at least an hour of my life, but that's not so bad.  If it wasn't kind of fun I wouldn't be monkeying with it on my day off!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1534850794621682982?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1534850794621682982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1534850794621682982' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1534850794621682982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1534850794621682982'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/06/new-rss-feed.html' title='New RSS feed'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-8418300356204186413</id><published>2010-06-04T13:25:00.001-07:00</published><updated>2010-06-04T13:46:18.962-07:00</updated><title type='text'>Allow Sendmail on Centos to accept connections on port 25</title><content type='html'>Need to use sendmail as an MTA?  It's running but your box is not accepting incoming connections on port 25?&lt;br /&gt;&lt;br /&gt;Perhaps you need to do this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The default sendmail.cf file does not allow Sendmail to accept network connections from any host other than the local computer. To configure Sendmail as a server for other clients, edit the /etc/mail/sendmail.mc file, and either change the address specified in the Addr= option of the DAEMON_OPTIONS directive from 127.0.0.1 to the IP address of an active network device or comment out the DAEMON_OPTIONS directive all together by placing dnl at the beginning of the line. When finished, regenerate /etc/mail/sendmail.cf by executing the following command:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    m4 /etc/mail/sendmail.mc &gt; /etc/mail/sendmail.cf&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then restart the service.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-8418300356204186413?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/8418300356204186413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=8418300356204186413' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8418300356204186413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8418300356204186413'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/06/allow-sendmail-on-centos-to-accept.html' title='Allow Sendmail on Centos to accept connections on port 25'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4063561858453843113</id><published>2010-06-02T11:14:00.000-07:00</published><updated>2010-06-02T11:15:05.287-07:00</updated><title type='text'>A little something I need to remember...</title><content type='html'>To turn off expandtab for editing makefiles, put the following in your vimrc:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;autocmd FileType make setlocal noexpandtab&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4063561858453843113?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4063561858453843113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4063561858453843113' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4063561858453843113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4063561858453843113'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/06/little-something-i-need-to-remember.html' title='A little something I need to remember...'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-902420371564820941</id><published>2010-05-30T21:17:00.001-07:00</published><updated>2010-05-31T03:48:24.216-07:00</updated><title type='text'>Shrink PDF linux (command line)</title><content type='html'>gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET -sPAPERSIZE=a4 -dBATCH -sOutputFile=output.pdf input.pdf&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-902420371564820941?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/902420371564820941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=902420371564820941' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/902420371564820941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/902420371564820941'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/05/shrink-pdf-linux-command-line.html' title='Shrink PDF linux (command line)'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4202039055076320206</id><published>2010-05-20T14:04:00.001-07:00</published><updated>2010-05-20T14:04:42.359-07:00</updated><title type='text'>Just for fun</title><content type='html'>&lt;pre&gt;&lt;br /&gt; .file "tiny.cpp"&lt;br /&gt; .local _ZStL8__ioinit&lt;br /&gt; .comm _ZStL8__ioinit,1,1&lt;br /&gt; .section .rodata&lt;br /&gt;.LC0:&lt;br /&gt; .string "Hello World"&lt;br /&gt; .text&lt;br /&gt;.globl main&lt;br /&gt; .type main, @function&lt;br /&gt;main:&lt;br /&gt;.LFB957:&lt;br /&gt; .cfi_startproc&lt;br /&gt; .cfi_personality 0x0,__gxx_personality_v0&lt;br /&gt; pushl %ebp&lt;br /&gt; .cfi_def_cfa_offset 8&lt;br /&gt; movl %esp, %ebp&lt;br /&gt; .cfi_offset 5, -8&lt;br /&gt; .cfi_def_cfa_register 5&lt;br /&gt; andl $-16, %esp&lt;br /&gt; subl $16, %esp&lt;br /&gt; movl $.LC0, 4(%esp)&lt;br /&gt; movl $_ZSt4cout, (%esp)&lt;br /&gt; call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc&lt;br /&gt; movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)&lt;br /&gt; movl %eax, (%esp)&lt;br /&gt; call _ZNSolsEPFRSoS_E&lt;br /&gt; movl $0, %eax&lt;br /&gt; leave&lt;br /&gt; ret&lt;br /&gt; .cfi_endproc&lt;br /&gt;.LFE957:&lt;br /&gt; .size main, .-main&lt;br /&gt; .type _Z41__static_initialization_and_destruction_0ii, @function&lt;br /&gt;_Z41__static_initialization_and_destruction_0ii:&lt;br /&gt;.LFB966:&lt;br /&gt; .cfi_startproc&lt;br /&gt; .cfi_personality 0x0,__gxx_personality_v0&lt;br /&gt; pushl %ebp&lt;br /&gt; .cfi_def_cfa_offset 8&lt;br /&gt; movl %esp, %ebp&lt;br /&gt; .cfi_offset 5, -8&lt;br /&gt; .cfi_def_cfa_register 5&lt;br /&gt; subl $24, %esp&lt;br /&gt; cmpl $1, 8(%ebp)&lt;br /&gt; jne .L5&lt;br /&gt; cmpl $65535, 12(%ebp)&lt;br /&gt; jne .L5&lt;br /&gt; movl $_ZStL8__ioinit, (%esp)&lt;br /&gt; call _ZNSt8ios_base4InitC1Ev&lt;br /&gt; movl $_ZNSt8ios_base4InitD1Ev, %eax&lt;br /&gt; movl $__dso_handle, 8(%esp)&lt;br /&gt; movl $_ZStL8__ioinit, 4(%esp)&lt;br /&gt; movl %eax, (%esp)&lt;br /&gt; call __cxa_atexit&lt;br /&gt;.L5:&lt;br /&gt; leave&lt;br /&gt; ret&lt;br /&gt; .cfi_endproc&lt;br /&gt;.LFE966:&lt;br /&gt; .size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii&lt;br /&gt; .type _GLOBAL__I_main, @function&lt;br /&gt;_GLOBAL__I_main:&lt;br /&gt;.LFB967:&lt;br /&gt; .cfi_startproc&lt;br /&gt; .cfi_personality 0x0,__gxx_personality_v0&lt;br /&gt; pushl %ebp&lt;br /&gt; .cfi_def_cfa_offset 8&lt;br /&gt; movl %esp, %ebp&lt;br /&gt; .cfi_offset 5, -8&lt;br /&gt; .cfi_def_cfa_register 5&lt;br /&gt; subl $24, %esp&lt;br /&gt; movl $65535, 4(%esp)&lt;br /&gt; movl $1, (%esp)&lt;br /&gt; call _Z41__static_initialization_and_destruction_0ii&lt;br /&gt; leave&lt;br /&gt; ret&lt;br /&gt; .cfi_endproc&lt;br /&gt;.LFE967:&lt;br /&gt; .size _GLOBAL__I_main, .-_GLOBAL__I_main&lt;br /&gt; .section .ctors,"aw",@progbits&lt;br /&gt; .align 4&lt;br /&gt; .long _GLOBAL__I_main&lt;br /&gt; .weakref _ZL20__gthrw_pthread_oncePiPFvvE,pthread_once&lt;br /&gt; .weakref _ZL27__gthrw_pthread_getspecificj,pthread_getspecific&lt;br /&gt; .weakref _ZL27__gthrw_pthread_setspecificjPKv,pthread_setspecific&lt;br /&gt; .weakref _ZL22__gthrw_pthread_createPmPK14pthread_attr_tPFPvS3_ES3_,pthread_create&lt;br /&gt; .weakref _ZL20__gthrw_pthread_joinmPPv,pthread_join&lt;br /&gt; .weakref _ZL21__gthrw_pthread_equalmm,pthread_equal&lt;br /&gt; .weakref _ZL20__gthrw_pthread_selfv,pthread_self&lt;br /&gt; .weakref _ZL22__gthrw_pthread_detachm,pthread_detach&lt;br /&gt; .weakref _ZL22__gthrw_pthread_cancelm,pthread_cancel&lt;br /&gt; .weakref _ZL19__gthrw_sched_yieldv,sched_yield&lt;br /&gt; .weakref _ZL26__gthrw_pthread_mutex_lockP15pthread_mutex_t,pthread_mutex_lock&lt;br /&gt; .weakref _ZL29__gthrw_pthread_mutex_trylockP15pthread_mutex_t,pthread_mutex_trylock&lt;br /&gt; .weakref _ZL31__gthrw_pthread_mutex_timedlockP15pthread_mutex_tPK8timespec,pthread_mutex_timedlock&lt;br /&gt; .weakref _ZL28__gthrw_pthread_mutex_unlockP15pthread_mutex_t,pthread_mutex_unlock&lt;br /&gt; .weakref _ZL26__gthrw_pthread_mutex_initP15pthread_mutex_tPK19pthread_mutexattr_t,pthread_mutex_init&lt;br /&gt; .weakref _ZL29__gthrw_pthread_mutex_destroyP15pthread_mutex_t,pthread_mutex_destroy&lt;br /&gt; .weakref _ZL30__gthrw_pthread_cond_broadcastP14pthread_cond_t,pthread_cond_broadcast&lt;br /&gt; .weakref _ZL27__gthrw_pthread_cond_signalP14pthread_cond_t,pthread_cond_signal&lt;br /&gt; .weakref _ZL25__gthrw_pthread_cond_waitP14pthread_cond_tP15pthread_mutex_t,pthread_cond_wait&lt;br /&gt; .weakref _ZL30__gthrw_pthread_cond_timedwaitP14pthread_cond_tP15pthread_mutex_tPK8timespec,pthread_cond_timedwait&lt;br /&gt; .weakref _ZL28__gthrw_pthread_cond_destroyP14pthread_cond_t,pthread_cond_destroy&lt;br /&gt; .weakref _ZL26__gthrw_pthread_key_createPjPFvPvE,pthread_key_create&lt;br /&gt; .weakref _ZL26__gthrw_pthread_key_deletej,pthread_key_delete&lt;br /&gt; .weakref _ZL30__gthrw_pthread_mutexattr_initP19pthread_mutexattr_t,pthread_mutexattr_init&lt;br /&gt; .weakref _ZL33__gthrw_pthread_mutexattr_settypeP19pthread_mutexattr_ti,pthread_mutexattr_settype&lt;br /&gt; .weakref _ZL33__gthrw_pthread_mutexattr_destroyP19pthread_mutexattr_t,pthread_mutexattr_destroy&lt;br /&gt; .ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"&lt;br /&gt; .section .note.GNU-stack,"",@progbits&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4202039055076320206?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4202039055076320206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4202039055076320206' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4202039055076320206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4202039055076320206'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/05/just-for-fun.html' title='Just for fun'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-5985820964018018797</id><published>2010-05-04T13:48:00.000-07:00</published><updated>2011-05-22T13:28:53.482-07:00</updated><title type='text'>Inversion of Control pattern</title><content type='html'>I'm not a huge fan of the so-called Inversion of Control pattern.  One blogger at theburningmonk.com writes, "You have Macaroni code when your application is chopped up into many little pieces and it's difficult to see the big picture which may exist only in your (or some one else's!) head."&lt;br /&gt;&lt;br /&gt;Another blogger says, "In software design, you can often end up with Macaroni code when you overuse/misuse/abuse abstractions, and it's one of the main dangers of using Inversion of Control."&lt;br /&gt;&lt;br /&gt;This echoes my own thoughts on the matter.  It's all well and good to work toward code reuse, and encapsulation is a worthy goal.  In my mind the DRY principal is the most important thing.  Many ills of poor software design can be cured simply by keeping the code compact, elegant and devoid of redundancy regardless of whether or not the code is procedural, object-oriented, or tiny atomic classes bound together by an XML configuration file.&lt;br /&gt;&lt;br /&gt;Procedural code gets a bad rap, as if code is inferior simply because it has a well defined entry and exit point.  It's beautiful thing when a debugger can be used to examine a code path from end to end.  It's beautiful when you can see the whole picture with your own eyes on a single page.  No diagrams needed to comprehend...no scrolling through hundreds of lines of XML to find the relationships.  It's all right there in the source code where it, very often, belongs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-5985820964018018797?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/5985820964018018797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=5985820964018018797' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5985820964018018797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5985820964018018797'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/05/railing-against-java-application.html' title='Inversion of Control pattern'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-3532126255308170256</id><published>2010-04-28T10:54:00.000-07:00</published><updated>2010-04-28T11:04:30.940-07:00</updated><title type='text'>Modes matter for password-less login</title><content type='html'>I typically setup keys to allow myself password-less access to remote development servers that I use all the time.  Today the typical ssh-keygen/deploy public-key routine didn't work as expected.  After deploying my public-key to the remote's authorized_keys, I still was getting prompted for a login.&lt;br /&gt;&lt;br /&gt;Found this in /var/log/secure.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Apr 28 12:51:35 theserver sshd[16285]: Authentication refused: bad ownership or modes for directory /home/theuser&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It turns out the the failure was due to the user's group permissions on the remote machine for two important folders.  Both the home folder and the .ssh folder had the following permissions: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;drwxrwx--- 36 theuser thegroup 4096 Apr 28 11:56 ..&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;chmod 700 for both /home/theuser and /home/theuser/.ssh fixed the problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-3532126255308170256?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/3532126255308170256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=3532126255308170256' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3532126255308170256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3532126255308170256'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/04/modes-matter-for-password-less-login.html' title='Modes matter for password-less login'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-2801356827107213100</id><published>2010-04-26T17:31:00.000-07:00</published><updated>2010-04-26T18:37:49.114-07:00</updated><title type='text'>Tulsa Developers tied to vendor technology</title><content type='html'>From time to time I take a look around to see what kind of programming talent is available in the Tulsa area.  Most of what I find is tied to Oracle/Sun (Java) or Microsoft.&lt;br /&gt;&lt;br /&gt;It's no secret that Tulsa has been heavy into Microsoft technology for years now.  The community colleges and trade schools teach it, the recruiters can get their heads around it, and many conservative businesses would rather go with a name they know.  &lt;br /&gt;&lt;br /&gt;I remember a Williams employee steering me away from my Borland c++ compiler many moons ago, assuring me that Visual c++ was the future.  &lt;br /&gt;&lt;br /&gt;Well it was and it wasn't.  I embraced Visual c++ and talked my first (serious) employer into letting me use it to write an application for a Phillips petroleum project. That work experience propelled me to my next development job, one I kept for almost a decade.  &lt;br /&gt;&lt;br /&gt;I wrote a heck of a lot of code using Visual c++ and the MFC framework, until it became my job to port the code to Unix flavors.  For days, weeks, months I chased the not-quite-regular constants, the libraries that were similar but rarely identical to the standards.  It was then that I started going cold on Microsoft.&lt;br /&gt;&lt;br /&gt;I moved away from Microsoft development tools for a lot of reasons including a strong preference for open-source.  There's so much free and truly open support on the web. When combined with Linux, open-source makes it possible to examine every nook and cranny of source code down to the kernel level.  &lt;br /&gt;&lt;br /&gt;Why would new developers gravitate to vendor tools when &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; they can't examine what is going on under the covers, &lt;/li&gt;&lt;br /&gt;&lt;li&gt; they can't control how long the technology will be supported before the vendor deprecates (or abandons) it in favor of new vendor tools, &lt;/li&gt;&lt;br /&gt;&lt;li&gt; they can't really have any substantial influence over the evolution of the technology?&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I was thinking about these questions as I reviewed search results for "tulsa developers".  It turns up these sites and not much more.&lt;br /&gt;&lt;br /&gt;www.tulsadnug.org&lt;br /&gt;&lt;br /&gt;tulsajava.com&lt;br /&gt;&lt;br /&gt;Tulsa seems to have a flourishing Microsoft and Java community.  Who is representing everything else that's happening in computer science?  &lt;br /&gt;&lt;br /&gt;According to Tiobe.com, the most popular programming language is JAVA.  Microsoft-based technology doesn't rank until the fifth position, and then it falls off except for position eight.  In Tulsa, I'm sure Visual Basic and C# would contend for two of the first three slots.&lt;br /&gt;&lt;br /&gt;1. Java - 19.1%&lt;br /&gt;2. C - 15.2%&lt;br /&gt;3. C++ - 10.1%&lt;br /&gt;4. PHP - 8.7%&lt;br /&gt;5. Visual Basic - 8.4%&lt;br /&gt;6. Perl - 6.2%&lt;br /&gt;7. Python - 3.8%&lt;br /&gt;8. C# - 3.7%&lt;br /&gt;9. JavaScript - 3.1%&lt;br /&gt;10. Ruby - 2.6%&lt;br /&gt;11. Delphi - 2.1%&lt;br /&gt;&lt;br /&gt;We all know that Tulsa, Oklahoma is a conservative city and not well known for risk taking.  And perhaps there is more to the story that a simple web query immediately reveals.  Ping.fm is Tulsa-based.  Python-friendly Vidoop was founded here, though they relocated and then folded.  Perhaps they should have stuck around.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-2801356827107213100?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/2801356827107213100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=2801356827107213100' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2801356827107213100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2801356827107213100'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/04/tulsa-developers-tied-to-vendor.html' title='Tulsa Developers tied to vendor technology'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4783008585082805835</id><published>2010-04-21T16:12:00.000-07:00</published><updated>2010-04-21T16:14:39.490-07:00</updated><title type='text'>Switch Primary Monitor in Ubuntu 10.4</title><content type='html'>The default Monitor Preferences dialog, while sweet, does not allow you to make your secondary monitor your primary. This is a problem if you want the top and bottom Ubuntu Panels displayed on the secondary monitor. Thankfully I found this sweet little script.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;#&lt;br /&gt;# Change Primary Monitor for Gnome&lt;br /&gt;# ver 1.0&lt;br /&gt;# &lt;br /&gt;# Copyright (c) 2010 michal@post.pl&lt;br /&gt;# &lt;br /&gt;# This file is free software. You can redistribute it &lt;br /&gt;# and/or modify it under the terms of the GNU&lt;br /&gt;# General Public License (GPL) as published by&lt;br /&gt;# the Free Software Foundation, in version 3.&lt;br /&gt;# It works for me. I hope it works for you as well.&lt;br /&gt;# NO WARRANTY of any kind. &lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# get list of top-level gnome panels&lt;br /&gt;getTopPanels() {&lt;br /&gt; gconftool-2 --all-dirs /apps/panel/toplevels&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# get monitor number for this panel&lt;br /&gt;getMonitor() {&lt;br /&gt; local PANEL=$1&lt;br /&gt; gconftool-2 --get $PANEL/monitor&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# set monitor to display on for given top-level panel&lt;br /&gt;setMonitor() {&lt;br /&gt; local PANEL=$1&lt;br /&gt; local NEW=$2&lt;br /&gt; gconftool-2 --set --type int $PANEL/monitor $NEW&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# return number of connected monitors&lt;br /&gt;getConnectedMonitors() {&lt;br /&gt; xrandr --query | grep -c '^.* connected'&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# compute next monitor&lt;br /&gt;nextMonitor() {&lt;br /&gt; # number of monitors&lt;br /&gt; local CURRENT=$1&lt;br /&gt; local MONITORS=$2&lt;br /&gt; awk 'BEGIN{ print ('$CURRENT' + 1) % '$MONITORS'; }'&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# logging finction&lt;br /&gt;log() {&lt;br /&gt; echo $@ 1&gt;&amp;2&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# main logic below #############&lt;br /&gt;&lt;br /&gt;MONITORS=`getConnectedMonitors`&lt;br /&gt;log "Detected $MONITORS connected monitors"&lt;br /&gt;&lt;br /&gt;getTopPanels | while read PANEL&lt;br /&gt;do&lt;br /&gt; MONITOR=`getMonitor $PANEL`&lt;br /&gt; NEW=`nextMonitor $MONITOR $MONITORS`&lt;br /&gt; log "Panel $PANEL is displayed on $MONITOR. Switching to monitor $NEW."&lt;br /&gt; setMonitor $PANEL $NEW&lt;br /&gt;done&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4783008585082805835?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4783008585082805835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4783008585082805835' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4783008585082805835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4783008585082805835'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/04/switch-primary-monitor-in-ubuntu-104.html' title='Switch Primary Monitor in Ubuntu 10.4'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-7717516833221891084</id><published>2010-04-15T07:06:00.000-07:00</published><updated>2010-04-15T07:41:45.928-07:00</updated><title type='text'>mod_security setup on Centos 5.4</title><content type='html'>Enable the EPEL repository.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Install via yum.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; yum install mod_security&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will load your basic mod_security configuration including the core rules.&lt;br /&gt;&lt;br /&gt;Next I had to set SecDataDir in the config.  This was not initially set and errors in the following form appeared in the log file.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ModSecurity: Unable to retrieve collection (name "&lt;key name&gt;", key "&lt;ip address&gt;"). Use SecDataDir to define data directory first.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Fixed this up by creating SecDataDir and creating a directory for this purpose, making sure to give apache permission to use it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;vim /etc/httpd/modsecurity.d/modsecurity_crs_10_config.conf &lt;br /&gt;( Added SecDataDir /usr/local/apache/modsec_data )&lt;br /&gt;mkdir /usr/local/apache&lt;br /&gt;mkdir /usr/local/apache/modsec_data&lt;br /&gt;chown apache:apache /usr/local/apache/modsec_data&lt;br /&gt;chown apache:apache /usr/local/apache&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After a restart modsecurity successfully began applying rules, but rather than blocking problem requests (my intention) it merely logged warnings.  I changed the SecDefaultAction in vim /etc/httpd/modsecurity.d/modsecurity_crs_10_config.conf from&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SecDefaultAction "phase:2,pass"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;to&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;SecDefaultAction "phase:2,deny,log,status:403"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;vim /etc/httpd/modsecurity.d/modsecurity_crs_10_config.conf&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-7717516833221891084?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/7717516833221891084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=7717516833221891084' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7717516833221891084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7717516833221891084'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/04/modsecurity-setup-on-centos-54.html' title='mod_security setup on Centos 5.4'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-8230144352571550816</id><published>2010-03-30T12:11:00.000-07:00</published><updated>2010-03-30T12:15:10.721-07:00</updated><title type='text'>Trouble using sockets in Django view</title><content type='html'>I ran into an issue while writing socket communication in code that was called by a Django view handler.  After a Twisted-based and socket-based solution failed mysteriously, I discovered a telnet-based solution that worked.  &lt;br /&gt;&lt;br /&gt;Read more about it the details here:&lt;br /&gt;&lt;br /&gt;http://wiki.devinvenable.com/mediawiki/index.php/Interesting_socket_behavior_exhibited_while_processing_Django_view&lt;br /&gt;&lt;br /&gt;Comments or insights as to the cause of the problem behavior would be helpful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-8230144352571550816?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/8230144352571550816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=8230144352571550816' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8230144352571550816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8230144352571550816'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/03/trouble-using-sockets-in-django-view.html' title='Trouble using sockets in Django view'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-967980523680575910</id><published>2010-03-25T08:32:00.001-07:00</published><updated>2010-03-25T13:17:12.959-07:00</updated><title type='text'>git merge</title><content type='html'>I used to work with a guy named Jay who, when encountering a particularly complex or difficult programming challenge, would state aloud, "Now that's powerful."&lt;br /&gt;&lt;br /&gt;git is a powerful tool.  And it really is but, my God, it sure has a way with obscure error messages.&lt;br /&gt;&lt;br /&gt;At some point you'll not be able to pull changes from the master (I want to call it the HEAD via cvs, svn concepts) because you are in the middle of a conflicted merge. You'll know this because you'll see this message:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;You are in the middle of a conflicted merge. &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Unlike svn update, which will pull the latest changes and automatically merge what can be merged and insert diffs where it can't, you need to manually merge the changes.  You can open the diff tool with this command:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git mergetool&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;mergetool doesn't actually work out the diffs---you do.  It opens a default diff editor for each file in need of merging, which may be vimdiff if nothing else is installed on your system.  You compare the differences, edit to make any changes, and save the file.  mergetool then asks you if the diff is complete, and if so, opens the next file.  This continues until you have resolved all conflicts.&lt;br /&gt;&lt;br /&gt;By the way, mergetool works with a number of different diff tools.  See the man page for a complete list.  I went with &lt;a href="http://meld.sourceforge.net/"&gt;meld&lt;/a&gt;, the gnome diff editor.  Once installed via apt-get, mergetool opened meld without any additional configuration.  Not quite sure how it knew which one I wanted, but it guessed and got it right.&lt;br /&gt;&lt;br /&gt;So now you can pull the latest changes, right?  Not so fast.  You might see an error like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;fatal: You have not concluded your merge. (MERGE_HEAD exists)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ah, what does it all mean?  I find this to be common thought when using git.  Clemens Buchacher had &lt;a href="http://n2.nabble.com/PATCH-refuse-to-merge-during-a-merge-td2983703.html"&gt;the answer&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;The following is an easy mistake to make for users coming from version &lt;br /&gt;control systems with an "update and commit"-style workflow. &lt;br /&gt;&lt;br /&gt;        1. git merge &lt;br /&gt;        2. resolve conflicts &lt;br /&gt;        3. git pull, instead of commit &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yes, that would be me: a fellow used to the "update and commit" style workflow.  &lt;br /&gt;&lt;br /&gt;For my case, I just had to commit once and then I could, finally, pull changes I had committed on another server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-967980523680575910?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/967980523680575910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=967980523680575910' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/967980523680575910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/967980523680575910'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/03/git-merge.html' title='git merge'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-7554547157530322482</id><published>2010-03-08T13:46:00.000-08:00</published><updated>2010-03-08T14:03:40.304-08:00</updated><title type='text'>Automounting removable eSata drive on Centos 5.4</title><content type='html'>So my boss says, "I don't get it.  When I have a gnome desktop open on the Centos box, my new eSata II removable mounts. But if I don't have a desktop open it doesn't get mounted when I reboot the box."&lt;br /&gt;&lt;br /&gt;I ask The Google about it, and it tells me:&lt;br /&gt;&lt;br /&gt;http://wiki.centos.org/TipsAndTricks/HAL&lt;br /&gt;&lt;br /&gt;But try as I might, gnome-volume-manager fails to detect and mount the eSata drive. The idea of running gnome daemons when in fact I'm working with a server in which gnome is rarely utilized (except for when my boss runs a remote desktop) gives me pause. Hmmm, I think, wouldn't this be a good job for udev rules?&lt;br /&gt;&lt;br /&gt;Running dmesg tells me that the device is present and that it's getting mounted as /dev/sdb1.  (Or you can tail /var/log/messages) Running the following gives me a list of attributes that are visible to udev on my device.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# udevinfo -a -p $(udevinfo -q path -n /dev/sdb)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With this is see several attributes which can be used for matching when the udev rules are applied.  I take the following two:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    SYSFS{rev}=="ST6O"&lt;br /&gt;    SYSFS{model}=="Hitachi HDT72101"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I want to mount the block device as /media/removable each time the device is plugged.  I also want to unmount when the device is removed.  The following worked for me.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ACTION=="add",SYSFS{rev}=="ST6O",SYSFS{model}=="Hitachi HDT72101",KERNEL=="sd?1",NAME="REMOVABLE", RUN+="/bin/mount /dev/REMOVABLE /media/removable"&lt;br /&gt;ACTION=="remove",SYSFS{rev}=="ST6O",SYSFS{model}=="Hitachi HDT72101",RUN+="/bin/umount /media/removable"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For more information, refer to this helpful page.&lt;br /&gt;&lt;br /&gt;http://reactivated.net/writing_udev_rules.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-7554547157530322482?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/7554547157530322482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=7554547157530322482' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7554547157530322482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7554547157530322482'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/03/automounting-removable-esata-drive-on.html' title='Automounting removable eSata drive on Centos 5.4'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4550136795806421476</id><published>2010-02-22T07:08:00.000-08:00</published><updated>2010-02-22T07:22:18.759-08:00</updated><title type='text'>strptime</title><content type='html'>Can't find strptime in datetime because you're working in a Python 2.4 environment?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Python 2.4.3 (#1, Jul 27 2009, 17:56:30) &lt;br /&gt;[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2&lt;br /&gt;Type "help", "copyright", "credits" or "license" for more information.&lt;br /&gt;&gt;&gt;&gt; from datetime import datetime&lt;br /&gt;&gt;&gt;&gt; d = datetime.strptime("21-JAN-08", "%d-%b-%y")&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "&lt;stdin&gt;", line 1, in ?&lt;br /&gt;AttributeError: type object 'datetime.datetime' has no attribute 'strptime'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;strptime was added to datetime in 2.5.  Prior to 2.5 you pull it from the typically lower-level library 'time'.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt;&gt;&gt; import time&lt;br /&gt;&gt;&gt;&gt; time.strptime("21-JAN-08", "%d-%b-%y")&lt;br /&gt;(2008, 1, 21, 0, 0, 0, 0, 21, -1)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ah, there it is.  Of course, you wanted a datetime, didn't you?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt;&gt;&gt; t = time.strptime("21-JAN-08", "%d-%b-%y")&lt;br /&gt;&gt;&gt;&gt; datetime(*t[0:6])&lt;br /&gt;&gt;&gt;&gt; datetime.datetime(2008, 1, 21, 0, 0)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4550136795806421476?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4550136795806421476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4550136795806421476' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4550136795806421476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4550136795806421476'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/02/strptime.html' title='strptime'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1846763846745748395</id><published>2010-02-09T10:38:00.001-08:00</published><updated>2010-02-09T10:52:25.942-08:00</updated><title type='text'>mod_mono, Centos 5 64 bit, and SELinux Part 2</title><content type='html'>The trick to creating a SELinux policy is setting the mode to be permissive, which prevents nothing but logs all of the infractions to audit.log, and then using the log to generate the policy.  After running my mod_mono based application for a bit in permissive mode, I used this command to generate a local policy.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;egrep 'http|mono' /var/log/audit/audit.log | audit2allow -M myhttp&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is the result:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;module myhttp 1.0;&lt;br /&gt;&lt;br /&gt;require {&lt;br /&gt; type httpd_tmp_t;&lt;br /&gt; type device_t;&lt;br /&gt; type initrc_t;&lt;br /&gt; type httpd_t;&lt;br /&gt; type httpd_sys_script_t;&lt;br /&gt; type http_port_t;&lt;br /&gt; type port_t;&lt;br /&gt; type inotifyfs_t;&lt;br /&gt; class process { execstack execmem getsched ptrace };&lt;br /&gt; class unix_stream_socket connectto;&lt;br /&gt; class chr_file { read write ioctl };&lt;br /&gt; class tcp_socket name_connect;&lt;br /&gt; class file execute;&lt;br /&gt; class sem { unix_read write unix_write associate read destroy };&lt;br /&gt; class shm { unix_read read write unix_write associate };&lt;br /&gt; class dir read;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#============= httpd_sys_script_t ==============&lt;br /&gt;allow httpd_sys_script_t http_port_t:tcp_socket name_connect;&lt;br /&gt;allow httpd_sys_script_t httpd_tmp_t:file execute;&lt;br /&gt;allow httpd_sys_script_t inotifyfs_t:dir read;&lt;br /&gt;allow httpd_sys_script_t self:process { execmem getsched ptrace };&lt;br /&gt;allow httpd_sys_script_t self:sem { unix_read write unix_write associate read destroy };&lt;br /&gt;&lt;br /&gt;#============= httpd_t ==============&lt;br /&gt;allow httpd_t device_t:chr_file { read write ioctl };&lt;br /&gt;allow httpd_t httpd_sys_script_t:unix_stream_socket connectto;&lt;br /&gt;allow httpd_t initrc_t:shm { unix_read read write unix_write associate };&lt;br /&gt;allow httpd_t port_t:tcp_socket name_connect;&lt;br /&gt;allow httpd_t self:process { execstack execmem };&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1846763846745748395?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1846763846745748395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1846763846745748395' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1846763846745748395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1846763846745748395'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/02/modmono-centos-5-64-bit-and-selinux_09.html' title='mod_mono, Centos 5 64 bit, and SELinux Part 2'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1625993131955630340</id><published>2010-02-08T08:28:00.001-08:00</published><updated>2010-02-08T11:07:21.199-08:00</updated><title type='text'>mod_mono, Centos 5 64 bit, and SELinux</title><content type='html'>Getting mod_mono up and running on Ubuntu 9.10 is relatively simple.  Install the packages, drop in a test asmx file, browse to the URL and you are done.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; &lt;br /&gt;apt-get install libapache2-mod-mono mono-apache-server2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My experience getting the same demo file with Centos 5 running SELinux was a bit more involved. First off, here's the complete simple web service.  You should be able to drop it into your document root and browse to the appropriate URL, once mod_mono is properly installed.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;%@ WebService Language="c#" Codebehind="TestService.asmx.cs" Class="WebServiceTests.TestService" %&gt;&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web.Services;&lt;br /&gt;using System.Web.Services.Protocols;&lt;br /&gt;&lt;br /&gt;namespace WebServiceTests&lt;br /&gt;{&lt;br /&gt;    public class TestService : System.Web.Services.WebService&lt;br /&gt;    {&lt;br /&gt;        [WebMethod]&lt;br /&gt;        public string Echo (string a)&lt;br /&gt;        {&lt;br /&gt;            return a;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [WebMethod]&lt;br /&gt;        public int Add (int a, int b)&lt;br /&gt;        {&lt;br /&gt;            return a + b;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On Centos 5, install these packages:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;yum install mod_mono xsp mono-web&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To enable mod_mono for Apache and run the xsp demo programs, add something like the following to the tail end of your http.conf file.  Be sure to check that the paths used here are the same on your machine.  (Note that I'm using a 64 bit Centos installation.)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;IfModule !mod_mono.c&gt;&lt;br /&gt;AddType application/x-asp-net .aspx&lt;br /&gt;AddType application/x-asp-net .asmx&lt;br /&gt;AddType application/x-asp-net .ashx&lt;br /&gt;AddType application/x-asp-net .asax&lt;br /&gt;AddType application/x-asp-net .ascx&lt;br /&gt;AddType application/x-asp-net .soap&lt;br /&gt;AddType application/x-asp-net .rem&lt;br /&gt;AddType application/x-asp-net .axd&lt;br /&gt;AddType application/x-asp-net .cs&lt;br /&gt;AddType application/x-asp-net .config&lt;br /&gt;AddType application/x-asp-net .Config&lt;br /&gt;AddType application/x-asp-net .dll&lt;br /&gt;AddType application/x-asp-net .asp&lt;br /&gt;DirectoryIndex index.aspx&lt;br /&gt;DirectoryIndex Default.aspx&lt;br /&gt;DirectoryIndex default.aspx&lt;br /&gt;&lt;/IfModule&gt;&lt;br /&gt;&lt;br /&gt;Alias /demo /usr/lib64/xsp/test&lt;br /&gt;MonoApplications "/demo:/usr/lib64/xsp/test"&lt;br /&gt;MonoServerPath /usr/bin/mod-mono-server&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You are likely to run into myriad problems if using SELinux. Start with giving permissions to run mono to httpd.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;chcon -t httpd_sys_content_t '/usr/bin/mono'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Each time you hit your URL you will likely encounter another SELinux error.  You can repeat this process again and again until you come up with a final policy that will allow apache access to mono, its directories, and dependencies.  My final policy looked like this.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;module mymono 1.0;&lt;br /&gt;&lt;br /&gt;require {&lt;br /&gt;        type lib_t;&lt;br /&gt;        type tmp_t;&lt;br /&gt;        type mono_exec_t;&lt;br /&gt;        type httpd_t;&lt;br /&gt;        type httpd_sys_script_t;&lt;br /&gt;        class process ptrace;&lt;br /&gt;        class sock_file { write create };&lt;br /&gt;        class sem create;&lt;br /&gt;        class file { read execute_no_trans };&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#============= httpd_sys_script_t ==============&lt;br /&gt;allow httpd_sys_script_t self:sem create;&lt;br /&gt;&lt;br /&gt;#============= httpd_t ==============&lt;br /&gt;allow httpd_t lib_t:file execute_no_trans;&lt;br /&gt;allow httpd_t mono_exec_t:file { read execute_no_trans };&lt;br /&gt;allow httpd_t self:process ptrace;&lt;br /&gt;allow httpd_t tmp_t:sock_file { write create };&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Mono makes extensive use of a temp directory known as the wapi directory.  It is possible for you to specify your own temp directory in your http.conf file or else the default will be used: /tmp/.wapi.&lt;br /&gt;&lt;br /&gt;It took awhile to discover that /tmp/.wapi needed different permissions.  The best clue I could get from messages was:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Feb  8 08:43:32 carbon setroubleshoot: SELinux is preventing the mono from using potentially mislabeled files (mod_mono_server_global). For complete SELinux messages. run sealert -l a00a5946-cec1-4291-a410-e74c5f96edfd&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This was corrected by running...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;restorecon -R -v /tmp/.wapi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;...as suggested by sealert.  &lt;br /&gt;&lt;br /&gt;Just as I thought I was finished, as the mono test application was finally working, I found additional errors in the /var/log/audit/audit.log.  This policy was the fix:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;module mynotify 1.0;&lt;br /&gt;&lt;br /&gt;require {&lt;br /&gt;        type httpd_t;&lt;br /&gt;        type inotifyfs_t;&lt;br /&gt;        class dir read;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#============= httpd_t ==============&lt;br /&gt;allow httpd_t inotifyfs_t:dir read;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Are we done yet?  I sure hope so.  I read elsewhere on the web that there is a plan to get the proper SELinux configuration into the mod_mono RPMs.  Until that happens, I hope that this info will help you to get your mod_mono setup working.&lt;br /&gt;&lt;br /&gt;Note:  After rebooting, I had to relabel the temp and bin directory with these two commands:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;restorecon -R -v /tmp/.wapi&lt;br /&gt;chcon -t httpd_sys_content_t '/usr/bin/mono'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I'm currently looking for a better, permanent solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1625993131955630340?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1625993131955630340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1625993131955630340' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1625993131955630340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1625993131955630340'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/02/modmono-centos-5-64-bit-and-selinux.html' title='mod_mono, Centos 5 64 bit, and SELinux'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-5002479557111081538</id><published>2010-01-25T11:56:00.000-08:00</published><updated>2010-01-26T08:04:53.443-08:00</updated><title type='text'>ISO 9797 algorithm 3</title><content type='html'>Last Friday I set out to implement ISO 9797 algorithm 3 using the OpenSSL library.  I did not have the specification handy, so I decided to to the best I could with what I could find by way of examples on the net.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I came across a description of the algorithm in this 2005 thread (http://www.derkeiler.com/Newsgroups/sci.crypt/2005-02/0374.html).  This was posted in a query by someone named Christian.  He also posted his keys, data and the expected answer.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;H0 = 0&lt;br /&gt;stages 1 to n: Hj = Enc(K, Dj XOR H{j-1})&lt;br /&gt;MAC = Enc(K, Dec(K', Hn))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Francois Grieu replied with, "This is very likely ISO/IEC 9797-1, using DES as the block cipher,&lt;br /&gt;padding method 2, MAC algorithm 3."  He provided an answer by sharing sample code in "some near-extinct dialect".&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;set m0 72C29C2371CC9BDB #message&lt;br /&gt;set m1 65B779B8E8D37B29&lt;br /&gt;set m2 ECC154AA56A8799F&lt;br /&gt;set m3 AE2F498F76ED92F2&lt;br /&gt;&lt;br /&gt;set pd 8000000000000000 #padding&lt;br /&gt;&lt;br /&gt;set iv 0000000000000000 #initialisation vector&lt;br /&gt;&lt;br /&gt;set k0 7962D9ECE03D1ACD #key&lt;br /&gt;set k1 4C76089DCE131543&lt;br /&gt;&lt;br /&gt;set xx {iv} # setup&lt;br /&gt;for mj in {m0} {m1} {m2} {m3} {pd} # for each block including padding&lt;br /&gt; set xx `xor {xx} {mj}` # chain&lt;br /&gt; set xx `des -k {k0} -c {xx}` #encrypt&lt;br /&gt;end&lt;br /&gt;set xx `des -k {k1} -d {xx}` #decrypt&lt;br /&gt;set xx `des -k {k0} -c {xx}` #encrypt&lt;br /&gt;echo {xx} #show result&lt;br /&gt;&lt;br /&gt;5F1448EEA8AD90A7 &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've implemented the same in c for the purpose of research. &lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp"&gt;&lt;br /&gt;#include openssl/des.h&lt;br /&gt;#include memory&lt;br /&gt;#include string.h&lt;br /&gt;&lt;br /&gt;//message + padding&lt;br /&gt;const unsigned char msg[40] = { 0x72, 0xC2, 0x9C, 0x23, 0x71, 0xCC, 0x9B, 0xDB,&lt;br /&gt;                              0x65, 0xB7, 0x79, 0xB8, 0xE8, 0xD3, 0x7B, 0x29,&lt;br /&gt;                              0xEC, 0xC1, 0x54, 0xAA, 0x56, 0xA8, 0x79, 0x9F,&lt;br /&gt;                              0xAE, 0x2F, 0x49, 0x8F, 0x76, 0xED, 0x92, 0xF2,&lt;br /&gt;                              0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };&lt;br /&gt;&lt;br /&gt;//initialization vector&lt;br /&gt;unsigned char iv[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };&lt;br /&gt;&lt;br /&gt;unsigned char k0[8] = { 0x79, 0x62, 0xD9, 0xEC, 0xE0, 0x3D, 0x1A, 0xCD };&lt;br /&gt;unsigned char k1[8] = { 0x4C, 0x76, 0x08, 0x9D, 0xCE, 0x13, 0x15, 0x43 };&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void print_hex(const unsigned char *bs, int n) {&lt;br /&gt;&lt;br /&gt;    for (int i = 0; i &lt; n; i++)&lt;br /&gt;        printf("%02x", bs[i]);&lt;br /&gt;    printf("\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void des_ecb_crypt(unsigned char* input, unsigned char* output, int encrypt, unsigned char* key) {&lt;br /&gt;&lt;br /&gt;    des_key_schedule sched;&lt;br /&gt;    des_set_key((des_cblock *) key, sched);&lt;br /&gt;&lt;br /&gt;    DES_ecb_encrypt((const_DES_cblock *)input,&lt;br /&gt;                     (const_DES_cblock *)output,&lt;br /&gt;                     &amp;sched,&lt;br /&gt;                     encrypt);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void xor_block(unsigned char* src, unsigned char* dest) {&lt;br /&gt;&lt;br /&gt;    for (int x = 0; x &lt; 8; x++) {&lt;br /&gt;       src[x] =  src[x] ^ dest[x];&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char* argv[]) {&lt;br /&gt;&lt;br /&gt;    unsigned char output[8];&lt;br /&gt;    unsigned char xx[8];&lt;br /&gt;    unsigned char block[8];&lt;br /&gt;    int offset = 0;&lt;br /&gt;&lt;br /&gt;    memcpy(xx, iv, 8);&lt;br /&gt;&lt;br /&gt;    // Chain and encrypt 5 8-bit blocks&lt;br /&gt;    for (int x = 0; x &lt; 5; x++) {&lt;br /&gt;&lt;br /&gt;        memcpy(block, &amp;msg[offset] , 8);&lt;br /&gt;        offset+=8;&lt;br /&gt;&lt;br /&gt;        //set xx `xor {xx} {mj}` # chain&lt;br /&gt;        xor_block(xx, block);&lt;br /&gt;&lt;br /&gt;        //set xx `des -k {k0} -c {xx}` #encrypt&lt;br /&gt;        des_ecb_crypt(xx, output, DES_ENCRYPT, k0);&lt;br /&gt;        memcpy(xx, output, 8);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    des_ecb_crypt(xx, output, DES_DECRYPT, k1);&lt;br /&gt;    memcpy(xx, output, 8);&lt;br /&gt;&lt;br /&gt;    des_ecb_crypt(xx, output, DES_ENCRYPT, k0);&lt;br /&gt;    memcpy(xx, output, 8);&lt;br /&gt;&lt;br /&gt;    print_hex(xx, 8);&lt;br /&gt;    return 1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-5002479557111081538?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/5002479557111081538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=5002479557111081538' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5002479557111081538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5002479557111081538'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/01/iso-9797-algorithm-3.html' title='ISO 9797 algorithm 3'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-9091365409214815716</id><published>2010-01-15T08:52:00.000-08:00</published><updated>2010-01-15T09:02:34.979-08:00</updated><title type='text'>Finding hidden characters in file using Vim</title><content type='html'>Show newlines and tab location:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;:set list&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Back to normal:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;:set nolist&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;View open file as hex:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;:%!xxd &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-9091365409214815716?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/9091365409214815716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=9091365409214815716' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/9091365409214815716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/9091365409214815716'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/01/finding-hidden-characters-in-file-using.html' title='Finding hidden characters in file using Vim'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1580726327145661159</id><published>2010-01-05T09:13:00.000-08:00</published><updated>2010-01-05T11:48:06.004-08:00</updated><title type='text'>Apache, mod_wsgi, Django, SELinux</title><content type='html'>I've come to rely on the fact that if something isn't working after an installation on Centos 5, it is probably due to bad SELinux permissions.   I've learned to live with SELinux and generally can handle any complication it throws at me.  I've learned to keep an eye on /var/log/messages and /var/log/audit/audit.log.  I've learned to use sealert and how to make my own local policies. Yet still it finds a way to throw me under the bus.&lt;br /&gt;&lt;br /&gt;This time around I'm installing Django under Apache.  I finally moved from mod_python to mod_wsgi.  With mod_wsgi, less configuration is needed in httpd.conf, but more is needed in an external config file.  For example, my original mod_python configuration looked like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;Directory "/var/www/html/python"&amp;gt;&lt;br /&gt;    AddHandler mod_python .py&lt;br /&gt;    PythonHandler mptest&lt;br /&gt;    PythonDebug On&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Location "/"&amp;gt;&lt;br /&gt;    SetHandler python-program&lt;br /&gt;    PythonHandler django.core.handlers.modpython&lt;br /&gt;    SetEnv DJANGO_SETTINGS_MODULE hsm.settings&lt;br /&gt;    PythonDebug On&lt;br /&gt;    PythonPath "['/home/stuff/src/python', '/home/stuff/src/python/hsm'] + sys.path"&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The second section is the Django deployment.  (The first I included to remind myself how simple it is to deploy a very basic  &lt;a href="http://www.modpython.org/live/mod_python-2.7.8/doc-html/inst-testing.html"&gt;test&lt;/a&gt; program using mod_python.  )&lt;br /&gt;&lt;br /&gt;With mod_wsgi, the apache config looks like this.  A single line identifies the location of the wsgi configuration, and the Directory element is used to give Apache permission to access the script.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;WSGIScriptAlias / /usr/local/www/wsgi-scripts/hsm.wsgi&lt;br /&gt;&lt;br /&gt;&amp;lt;Directory /usr/local/www/wsgi-scripts&amp;gt;&lt;br /&gt;Order allow,deny&lt;br /&gt;Allow from all&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My custom wsgi script includes these lines.  The last line keeps the wsgi handler from puking on &lt;br /&gt;print lines that might be included in your file.&lt;br /&gt;&lt;br /&gt;&lt;pre class="python"&gt;&lt;br /&gt;    import os&lt;br /&gt;    import sys&lt;br /&gt;&lt;br /&gt;    os.environ['DJANGO_SETTINGS_MODULE'] = 'hsm.settings'&lt;br /&gt;&lt;br /&gt;    import django.core.handlers.wsgi&lt;br /&gt;    application = django.core.handlers.wsgi.WSGIHandler()&lt;br /&gt;&lt;br /&gt;    sys.stdout = sys.stderr&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For this particular Django application, I decided to use sqlite3 instead of mysql.  But attempting to launch proved problematic.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]     return query.execute_sql(return_id)&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]   File "/usr/lib/python2.4/site-packages/django/db/models/sql/subqueries.py", line 320, in execute_sql&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]     cursor = super(InsertQuery, self).execute_sql(None)&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]   File "/usr/lib/python2.4/site-packages/django/db/models/sql/query.py", line 2369, in execute_sql&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]     cursor.execute(sql, params)&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]   File "/usr/lib/python2.4/site-packages/django/db/backends/util.py", line 19, in execute&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]     return self.cursor.execute(sql, params)&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]   File "/usr/lib/python2.4/site-packages/django/db/backends/sqlite3/base.py", line 193, in execute&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62]     return Database.Cursor.execute(self, query, params)&lt;br /&gt;[Tue Jan 05 11:02:08 2010] [error] [client 10.8.8.62] OperationalError: attempt to write a readonly database&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To read and write to the sqlite database, I had to:&lt;br /&gt;&lt;br /&gt;1. Ensure the database file and its parent directory was owned by the apache user.  (The location of the database file is specified in the Django settings.py file for your project.)&lt;br /&gt;&lt;br /&gt;2. Add a Directory entry to the httpd.conf file for the location of my database file.  By default, apache does not have access to directories not under DocumentRoot.&lt;br /&gt;&lt;br /&gt;3. Apply SELinux level permissions to the database file and its parent directory.&lt;br /&gt;&lt;br /&gt;It took me quite awhile to discover that I had SELinux level permissions because I did not receive notifications in the /var/log/messages file.  Normally all security exceptions arrive there and it is easy enough to tail the file and look for events.  For whatever reason, the alerts were not appearing in the log, &lt;span style="font-weight:bold;"&gt;at least not every time&lt;/span&gt;.  For example, the settroubleshoot alert browser (sealert -b) showed the exact problem that occurred at 11:02 AM (below), but the /var/log/messages file had no corresponding entry.  The log did have a similar message from 10:59.  The log either does not receive duplicate messages for SELinux events, or that some kind of bug is to blame. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Summary:&lt;br /&gt;&lt;br /&gt;SELinux is preventing the httpd from using potentially mislabeled files&lt;br /&gt;./sqlite3.db (usr_t).&lt;br /&gt;&lt;br /&gt;Detailed Description:&lt;br /&gt;&lt;br /&gt;SELinux has denied the httpd access to potentially mislabeled files&lt;br /&gt;./sqlite3.db. This means that SELinux will not allow httpd to use these files.&lt;br /&gt;Many third party apps install html files in directories that SELinux policy&lt;br /&gt;cannot predict. These directories have to be labeled with a file context which&lt;br /&gt;httpd can access.&lt;br /&gt;&lt;br /&gt;Allowing Access:&lt;br /&gt;&lt;br /&gt;If you want to change the file context of ./sqlite3.db so that the httpd daemon&lt;br /&gt;can access it, you need to execute it using chcon -t httpd_sys_content_t&lt;br /&gt;'./sqlite3.db'. You can look at the httpd_selinux man page for additional&lt;br /&gt;information.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The solution was to modify the SELinux permissions on the folder that contained the sqlite database:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo chcon -R system_u:object_r:httpd_sys_content_t database_folder&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hope this information will help the next unlucky person to deploy in a similar environment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1580726327145661159?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1580726327145661159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1580726327145661159' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1580726327145661159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1580726327145661159'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2010/01/apache-modwsgi-django-selinux.html' title='Apache, mod_wsgi, Django, SELinux'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-2214270578950535321</id><published>2009-12-28T06:50:00.000-08:00</published><updated>2009-12-28T07:35:04.856-08:00</updated><title type='text'>Compiling ZynAddSubFX on Ubuntu 9.04</title><content type='html'>ZynAddSubFX does not compile from source by default and there is no configure file.  Add the following packages and the build will succeed.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;apt-get install fluid libmxml-dev libfftw3-3 mffm-fftw-dev libasound2-dev&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've never been happy with the &lt;a href="http://www.flickr.com/photos/27165790@N06/4221768301/"&gt;appearance of ZynAddSubFX on linux&lt;/a&gt;.  It seemed the fonts were all too big, crowding the screen and buttons.  I was going to look into fixing this, which was the reason I downloaded the source version in the first place.  But to my surprise, &lt;a href="http://www.flickr.com/photos/27165790@N06/4222530134/"&gt;the version I compiled myself looked great&lt;/a&gt;.  I'm guessing that fluid makes geometric decisions based on the video display it is used on and that the package maintainer uses a lower screen resolution than I do, thus the crappy display.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-2214270578950535321?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/2214270578950535321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=2214270578950535321' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2214270578950535321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2214270578950535321'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/12/compiling-zynaddsubfx-on-ubuntu-904.html' title='Compiling ZynAddSubFX on Ubuntu 9.04'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-7569773771599354116</id><published>2009-12-24T18:04:00.001-08:00</published><updated>2009-12-24T18:26:05.745-08:00</updated><title type='text'>M-Audio / Freebob and Ubuntu 9.10</title><content type='html'>In setting up a new Ubuntu 9.10 install with ubuntustudio, I had to do a few manual things.  There is an UbuntuStudio distribution, but I typically opt to install what I need later, which is generally just the awesome audio stuff.  If you go this route and want to use jack, be sure to also install the real time kernel.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo apt-get install ubuntustudio-audio&lt;br /&gt;sudo apt-get install linux-rt&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I use a M-Audio FiewWire Solo audio card and have used the freebob driver with success in the past.  I was happy to see that it is installed by default now with qjackctl.  But when I started jack initially I got errors suggesting the driver was not loaded.  I had to install the driver and change permissions before I jack would start up.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo modprobe raw1397&lt;br /&gt;sudo chmod a+rw /dev/raw1394&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Chmod was transient however, and after rebooting /dev/raw1394 didn't have the correct permissions.  I added a file called 40-permissions.rules and gave the audio group permission to access the device.  I failed to mention earlier that I also had to add my personal user to the "audio" group before getting jack to start up.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sudo vim /etc/udev/rules.d/40-permissions.rules&lt;br /&gt;# EEE1394 (firewire) devices&lt;br /&gt;KERNEL=="raw1394",          GROUP="audio"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So I was done right? No.  After reboot I still didn't have permission to access the firewire device.  ls told me why.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ls -altr /dev/raw1394 &lt;br /&gt;crw-rw---- 1 root video 171, 0 2009-12-24 19:55 /dev/raw1394&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I guess by default /dev/raw1394 belongs to the video group.  Well my user doesn't, and I'm not using firewire for video, so I switched it to belong to audio.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;dextron@dextron:~$ sudo chgrp audio /dev/raw1394&lt;br /&gt;ls -altr /dev/raw1394 &lt;br /&gt;crw-rw---- 1 root audio 171, 0 2009-12-24 19:55 /dev/raw1394&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After another reboot, all is well.  I'm wondering if I should have just left the group as "video" and added my user to the video group plus changing my udev rule (to use video instead of audio).  I suspect there is no single right answer, but if you have any insights, please leave a comment.  Thanks!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-7569773771599354116?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/7569773771599354116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=7569773771599354116' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7569773771599354116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7569773771599354116'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/12/m-audio-freebob-and-ubuntu-910.html' title='M-Audio / Freebob and Ubuntu 9.10'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-3909581511667874767</id><published>2009-12-07T08:15:00.001-08:00</published><updated>2009-12-07T12:35:08.335-08:00</updated><title type='text'>Creating digital synth sounds using Python</title><content type='html'>I used to really be into electronic music.  I had a bunch of keyboards, synths and digital samplers and I would use them, along with a computer, to compose techno compositions. In fact, I took up c++ programming in the 90's with the intention of building a drum sequencer for Windows.  Well that project didn't get finished and I got sidetracked writing code for corporations; after all you have to pay the bills first and find time to play around later.&lt;br /&gt;&lt;br /&gt;Now seems like a good time to resume play.&lt;br /&gt;&lt;br /&gt;Since Python is my language of choice these days, I thought I'd see what's out there by way of using the language to generate digital sounds.  I found a wave generation library and a few sample snippets on the web, including code which can be used to produce a simple sine wave.  I've been sampling since the 80's using Roland, Ensoniq and EMU samplers, and I have a pretty good understanding of the basics.  But it turns out I had more to learn at the lowest level.  Consider the following snippet of code, which can be used to generate a 90 Hz tone.&lt;br /&gt;&lt;br /&gt;&lt;pre class="python"&gt;&lt;br /&gt;import wave, random, math, numpy&lt;br /&gt;&lt;br /&gt;noise_output = wave.open('tone.wav', 'w')&lt;br /&gt;noise_output.setparams((2, 2, 44100, 0, 'NONE', 'not compressed'))&lt;br /&gt;&lt;br /&gt;# num of seconds&lt;br /&gt;duration = 4&lt;br /&gt;&lt;br /&gt;# Hz per second&lt;br /&gt;samplerate = 44100&lt;br /&gt;&lt;br /&gt;# total number of samples&lt;br /&gt;samples = duration * samplerate&lt;br /&gt;&lt;br /&gt;# pulse per second&lt;br /&gt;frequency = 90 # Hz&lt;br /&gt;&lt;br /&gt;"""&lt;br /&gt;The time of one sample is the inverse of the sample rate, and the period is the inverse of the frequency, so the number of samples is also the sample rate divided by the frequency.&lt;br /&gt;"""&lt;br /&gt;period = samplerate / float(frequency) # in sample points&lt;br /&gt;&lt;br /&gt;"""&lt;br /&gt;This is the phase increment.&lt;br /&gt;"""&lt;br /&gt;omega = numpy.pi * .2 / period&lt;br /&gt;&lt;br /&gt;"""&lt;br /&gt;Creates the x-axis set with 'period' number of items.  numpy.arange(int(period), dtype = numpy.float) produces {0..146}, but since each value is a factor of omega, the transformed set is in the range {0..0.627}.&lt;br /&gt;"""&lt;br /&gt;xaxis = numpy.arange(int(period), dtype = numpy.float) * omega&lt;br /&gt;&lt;br /&gt;"""&lt;br /&gt;This snippet calculates the sin for each value in xaxis and multiplies that value with 16384.  Here we're creating the y-axis data.&lt;br /&gt;"""&lt;br /&gt;ydata = 16384 * numpy.sin(xaxis)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;"""&lt;br /&gt;If we were to graph the sets now, we would see an inclining sin wave.  Resize creates an extended array which repeats the ydata chunk, the result being something that looks a bit more like a saw wave than a sin wave due to the omega calculation.&lt;br /&gt;"""&lt;br /&gt;signal = numpy.resize(ydata, (samples,))&lt;br /&gt;&lt;br /&gt;for i in signal:&lt;br /&gt;    packed_value = wave.struct.pack('h', i)&lt;br /&gt;    noise_output.writeframes(packed_value)&lt;br /&gt;&lt;br /&gt;noise_output.close()&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;http://en.wikipedia.org/wiki/Direct_digital_synthesis&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-3909581511667874767?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/3909581511667874767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=3909581511667874767' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3909581511667874767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3909581511667874767'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/12/creating-digital-synth-sounds-using.html' title='Creating digital synth sounds using Python'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-7092648003286821048</id><published>2009-12-04T06:41:00.000-08:00</published><updated>2009-12-04T06:46:32.261-08:00</updated><title type='text'>Find all non-binary files in a directory</title><content type='html'>You've got to love that there are so many different ways to accomplish this.  Here's one:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;find . -type f | xargs file | grep -v ELF&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;1.  Recursively finds all files in current directory&lt;br /&gt;2.  Pipes to file, which displays information about each file type&lt;br /&gt;3.  Pipes to grep, which checks to see that ELF is NOT in result text&lt;br /&gt;&lt;br /&gt;file is a handy command.  On Linux, binary files with show something like the following.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;dvenable@dvenable:~/src$ file bin.exe&lt;br /&gt;bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-7092648003286821048?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/7092648003286821048/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=7092648003286821048' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7092648003286821048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7092648003286821048'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/12/find-all-non-binary-files-in-directory.html' title='Find all non-binary files in a directory'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-2662076015641563025</id><published>2009-12-03T07:01:00.000-08:00</published><updated>2009-12-03T07:12:03.269-08:00</updated><title type='text'>Save with CTRL-S using VIM and copy/paste with CTRL-C, CTRL-V</title><content type='html'>Oh now this has got to be the best VIM find in years.  I love VIM but get sick of copying from a web browser and having to visual paste in strange ways.  It's my one holdover from Windows, the desire to use CTRL-C to copy and CTRL-V to paste.  It turns out that this is easily remedied by modifying your .vimrc file and adding VIM mappings.  &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;nmap &amp;lt;C-V&amp;gt; "+gP&lt;br /&gt;imap &amp;lt;C-V&amp;gt; &amp;lt;ESC&amp;gt;&amp;lt;C-V&amp;gt;i&lt;br /&gt;vmap &amp;lt;C-C&amp;gt; "+y&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's it.  Now enjoy the most standard shortcuts in your favorite VIM editor.  The mappings looked so easy that I thought I'd try one of my own.  Another thing that causes my fingers to grow weary is saving.  The typical sequence is: press escape, then :w enter.  I save all the time because I'm paranoid and I miss CTRL-S which is so much easier on the hands.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;map &amp;lt;C-S&amp;gt; &amp;lt;ESC&amp;gt;:w&amp;lt;CR&amp;gt;&lt;br /&gt;imap &amp;lt;C-S&amp;gt; &amp;lt;ESC&amp;gt;:w&amp;lt;CR&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Oh yes it is a sweet discovery!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-2662076015641563025?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/2662076015641563025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=2662076015641563025' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2662076015641563025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2662076015641563025'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/12/save-with-ctrl-s-using-vim-and.html' title='Save with CTRL-S using VIM and copy/paste with CTRL-C, CTRL-V'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6860574503098669670</id><published>2009-11-30T11:55:00.000-08:00</published><updated>2009-11-30T12:01:09.906-08:00</updated><title type='text'>Multi-file search and replace one-liner</title><content type='html'>&lt;pre&gt;&lt;br /&gt;find . -name  "*.ksh" -exec sed -i 's/oldtext/newtext/g' {} \;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6860574503098669670?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6860574503098669670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6860574503098669670' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6860574503098669670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6860574503098669670'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/11/multi-file-search-and-replace-one-liner.html' title='Multi-file search and replace one-liner'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4573272068818314461</id><published>2009-11-17T07:34:00.001-08:00</published><updated>2009-11-17T07:37:06.874-08:00</updated><title type='text'>Centos 5, SELinux, and Bugzilla</title><content type='html'>I really don't like SELinux.  There.  I said it.&lt;br /&gt;&lt;br /&gt;After installing bugzilla from the yum repository I found that it could not send email notifications.  Why?  SELinux.  The solution? Here.&lt;br /&gt;&lt;br /&gt;&lt;pre class="bash"&gt;&lt;br /&gt;[dvenable@somecorporateserver ~]$ sudo chcon -R --reference=/var/www/html /usr/share/bugzilla&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4573272068818314461?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4573272068818314461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4573272068818314461' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4573272068818314461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4573272068818314461'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/11/centos-5-selinux-and-bugzilla.html' title='Centos 5, SELinux, and Bugzilla'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-9087794764036250391</id><published>2009-11-13T06:14:00.000-08:00</published><updated>2009-11-13T08:49:15.966-08:00</updated><title type='text'>KVM on Centos 5</title><content type='html'>I've been a XEN man for sometime now, but yesterday my employer asked me to set up KVM on one of our Centos 5 servers.  It was a snap.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Installation&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; yum install kvm qemu virt-manager libvirt&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The next step is to modprobe the kvm module for your architecture. Use the module that is right for you:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; modprobe kvm-intel&lt;br /&gt; ...or...&lt;br /&gt; modprobe kvm-amd&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If all goes well, you should have the kvm module loaded on your system by now. You can check this by running:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; /sbin/lsmod | grep kvm&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Setup the Bridge&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you want to access the virtual machine from the LAN, you'll need to set up a bridge on one or more of your network interfaces.  Once this step is complete, virt-manager will take care of the remaining details when setting up a virtual machine using the GUI.&lt;br /&gt;&lt;br /&gt;Check that a default bridge is configured. Run brctl show and you should see something like this.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; [root@server ~]# brctl show&lt;br /&gt; bridge name bridge id  STP enabled interfaces&lt;br /&gt; virbr0  8000.000000000000 yes  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What you should see is a line that includes vnet0.  Don't screw the pooch like I did and use virbr0 if vnet0 is not listed.  virbr0 is used by NAT and you will hose the system if you go this route.  IF vnet0 is not listed, restart networking.  If still not present, use Google to resolve before continuing.  Your goal is to see this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bridge name bridge id  STP enabled interfaces&lt;br /&gt;virbr0  8000.000000000000 yes  &lt;br /&gt;vnet0  8000.000000000000 no &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Create a file in network-scripts called ifcfg-vnet0...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; vim /etc/sysconfig/network-scripts/ifcfg-vnet0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;...and add the following if you want to configure the bridge for eth0:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; DEVICE=vnet0&lt;br /&gt; TYPE=Bridge&lt;br /&gt; BOOTPROTO=dhcp&lt;br /&gt; ONBOOT=yes&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now add the bridge:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  brctl addif vnet0 eth0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now you'll see:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; [root@server ~]# brctl show&lt;br /&gt; bridge name bridge id  STP enabled interfaces&lt;br /&gt; virbr0  8000.000000000000 yes  &lt;br /&gt; vnet0  8000.003048625732 no  eth0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To make this sticky (available after reboot), add BRIDGE=vnet0 to /etc/sysconfig/network-scripts/ifcfg-eth0.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Create the Virtual Machine&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It's possible to create a virtual machine from the command line like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; qemu-kvm -hda windisk.img -cdrom winimg.iso -m 1024 -boot d&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;However, it's probably easier to manage things using virt-manager.  Launch from the UI or from the command line.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; virt-manager&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Click on the first row to highlight it, right-click and select new to open the wizard.  Follow the steps including choice of ISO and where to write the image. When you get to the network screen, choose Shared Physical Device and you will see your bridged eth0 interface.  If you skipped bridging, you will not have this option so take a different one.&lt;br /&gt;&lt;br /&gt;Once complete, start up the VM.  Done.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-9087794764036250391?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/9087794764036250391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=9087794764036250391' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/9087794764036250391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/9087794764036250391'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/11/kvm-on-centos-5.html' title='KVM on Centos 5'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6968533756808734891</id><published>2009-11-06T06:04:00.000-08:00</published><updated>2009-11-10T05:45:46.438-08:00</updated><title type='text'>Migrating schema from Oracle 11g Enterprise to 10g Express Edition</title><content type='html'>Here's the situation: you are working in an environment that uses Oracle Enterprise 11g, you want to do some development on your personal computer using your own database, and for whatever reason you cannot simply install a full-blown non-free version of Oracle on your laptop.&lt;br /&gt;&lt;br /&gt;Your best free option is to install Oracle 10g XE, especially if you are running Ubuntu because installation is a snap.&lt;br /&gt;&lt;br /&gt;http://www.oracle.com/technology/tech/linux/install/xe-on-kubuntu.html&lt;br /&gt;&lt;br /&gt;Of course you should know that XE is stripped down, so read up and make sure that you won't be losing features that you'll absolutely need to run your production or test database.&lt;br /&gt;&lt;br /&gt;The first step is to export your database.  If you're like me an you attempt to simply export using the exp tool that ships with 11g, you will discover that there are incompatibilities between version which will prevent you from importing with 10g XE.&lt;br /&gt;&lt;br /&gt;The easy solution?  Just use the 10g version of the tools that ship with XE to dump the 11g database.  In my environment, everything is Linux, so my quick-and-dirty approach was to create a temp directory on the 11g server and scp the 10g version of exp over to it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;cd $ORACLE_HOME/bin&lt;br /&gt;scp exp me@11gserver:~/temp&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Of course I don't have the needed 10g libs on the 11g server, so I just copy the all Oracle libs over to the same directory.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;scp /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/lib/* me@11gserver:~/temp&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now I ssh over to the 11g server and set up my environment to add the current directory (temp) to the LD_LIBRARY_PATH.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;export LD_LIBRARY_PATH=.:/usr/lib32:/usr/local/lib32&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now to dump...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;exp SYSTEM/stuff@11gserver:1521/yeah.stuff.com FILE=export.dmp OWNER=me_the_owner&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now copy the resulting export.dmp file back to your target computer, the one running 10g XE.  (You know how to do it!)&lt;br /&gt;&lt;br /&gt;Okay, now cross your fingers and attempt the import, hoping to succeed though you just know that critical 11g features won't be supported on XE and will probably cause all your effort to be for naught.  But do it anyway.&lt;br /&gt;&lt;br /&gt;In my case I now yell "Doh!" because I get the same damn error I had before.  Did I mention the error?  Yes, the one I got after importing initially, the export file created using 11g's exp.  This is what I see on my development laptop.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;imp SYSTEM/xx FILE=/home/me/export.dmp FULL=y&lt;br /&gt;&lt;br /&gt;Import: Release 10.2.0.1.0 - Production on Fri Nov 6 08:32:09 2009&lt;br /&gt;&lt;br /&gt;Copyright (c) 1982, 2005, Oracle.  All rights reserved.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Connected to: Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production&lt;br /&gt;&lt;br /&gt;IMP-00010: not a valid export file, header failed verification&lt;br /&gt;IMP-00000: Import terminated unsuccessfully&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I check the head...aha I see my error.  I was still using the darn 11g exp because I failed to put the 10g exp on the path on the 11g server before I ran exp.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; head export.dmp &lt;br /&gt;EXPORT:V11.01.00&lt;br /&gt;DSYSTEM&lt;br /&gt;RUSERS&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Oh, and in case you are thinking you might just break out a HEX editor and change the EXPORT version in the header to the correct version, it won't work.  Yes I thought of that too.&lt;br /&gt;&lt;br /&gt;Okay, back to the 11g server to re-run.  This time notice the ./ before exp to pick up the correct version of the executable.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;./exp SYSTEM/stuff@11gserver:1521/yeah.stuff.com FILE=export.dmp OWNER=me_the_owner&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Once you "get it right" move the export back to your development box.  In my case, I had to create matching tablespaces and users before the importing with success.  Once that was done, I ran the following...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;imp SYSTEM/xx FILE=/home/me/export.dmp FULL=Y &lt;br /&gt;...&lt;br /&gt;lots of output here, such as&lt;br /&gt; row rejected due to ORACLE error 12899&lt;br /&gt;...&lt;br /&gt;Import terminated successfully with warnings.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I believe my warnings are due to character set incompatibilities, and since I'm set to blow up this copy of the database in a development environment anyway, I'm not going to research them now.&lt;br /&gt;&lt;br /&gt;I fired up SqlDeveloper, connected to my 10g XE instance, and selected some data.  No problem!  Who says you can't move an Oracle Enterprise 11g database to Oracle 10g XE?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6968533756808734891?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6968533756808734891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6968533756808734891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6968533756808734891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6968533756808734891'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/11/migrating-schema-from-oracle-enterprise.html' title='Migrating schema from Oracle 11g Enterprise to 10g Express Edition'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-8353992464333159494</id><published>2009-10-30T09:18:00.000-07:00</published><updated>2009-10-30T09:25:31.372-07:00</updated><title type='text'>Netbeans and Make</title><content type='html'>Netbeans for c++ uses the standard make tools.  The top level Makefile is always the same for every project and is the correct place to add custom build steps.  The nbproject subproject files are modified by the NetBeans editor, so it is best to avoid making changes there.&lt;br /&gt;&lt;br /&gt;There are hooks in the top-level make where various custom steps can be inserted.&lt;br /&gt;&lt;br /&gt;&lt;pre class="bash"&gt;&lt;br /&gt;#&lt;br /&gt;#  There exist several targets which are by default empty and which can be &lt;br /&gt;#  used for execution of your targets. These targets are usually executed &lt;br /&gt;#  before and after some main targets. They are: &lt;br /&gt;#&lt;br /&gt;#     .build-pre:              called before 'build' target&lt;br /&gt;#     .build-post:             called after 'build' target&lt;br /&gt;#     .clean-pre:              called before 'clean' target&lt;br /&gt;#     .clean-post:             called after 'clean' target&lt;br /&gt;#     .clobber-pre:            called before 'clobber' target&lt;br /&gt;#     .clobber-post:           called after 'clobber' target&lt;br /&gt;#     .all-pre:                called before 'all' target&lt;br /&gt;#     .all-post:               called after 'all' target&lt;br /&gt;#     .help-pre:               called before 'help' target&lt;br /&gt;#     .help-post:              called after 'help' target&lt;br /&gt;#&lt;br /&gt;#  Targets beginning with '.' are not intended to be called on their own&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can also add your own targets, just as if you were building a makefile from scratch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-8353992464333159494?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/8353992464333159494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=8353992464333159494' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8353992464333159494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8353992464333159494'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/10/netbeans-and-make.html' title='Netbeans and Make'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6734581596553603291</id><published>2009-10-27T05:50:00.000-07:00</published><updated>2009-11-17T12:26:55.231-08:00</updated><title type='text'>Generating HTML color syntax highlighting from PRE tag</title><content type='html'>I'm working on a Django template tag that should transform code embedded within a PRE tag and convert it to nicely formatted HTML with color syntax.  To test, I inserted this block of code here, the same code I wrote to do the conversion.&lt;br /&gt;&lt;br /&gt;&lt;pre class="python"&gt;&lt;br /&gt;#!/usr/bin/python&lt;br /&gt;&lt;br /&gt;from django import template&lt;br /&gt;from django.template.defaultfilters import stringfilter&lt;br /&gt;from django.utils.safestring import mark_safe&lt;br /&gt;from BeautifulSoup import BeautifulSoup&lt;br /&gt;from pygments.lexers import guess_lexer, guess_lexer_for_filename&lt;br /&gt;from pygments import highlight&lt;br /&gt;from pygments.lexers import get_lexer_by_name, TextLexer&lt;br /&gt;from pygments.formatters import HtmlFormatter&lt;br /&gt;import re&lt;br /&gt;&lt;br /&gt;register = template.Library()&lt;br /&gt;&lt;br /&gt;@stringfilter&lt;br /&gt;def tocode(value):&lt;br /&gt;    try:&lt;br /&gt;        commentSoup = BeautifulSoup(value)&lt;br /&gt;        c = commentSoup.findAll('pre')&lt;br /&gt;        for all in c:&lt;br /&gt;            brs = all.findAll('br')&lt;br /&gt;            for item in brs:&lt;br /&gt;                item.replaceWith('\n')&lt;br /&gt;            joined = ''.join(all.findAll(text=True))&lt;br /&gt;&lt;br /&gt;            if all.has_key('class'):&lt;br /&gt;                lex = get_lexer_by_name(all['class'], stripall=True)&lt;br /&gt;            else:&lt;br /&gt;                try:&lt;br /&gt;                    lex = guess_lexer(joined)&lt;br /&gt;                except:&lt;br /&gt;                    lex = BashSessionLexer&lt;br /&gt;            formatter = HtmlFormatter(linenos=True, cssclass="source")&lt;br /&gt;            result = highlight(joined, lex, formatter)&lt;br /&gt;            all.replaceWith(result)&lt;br /&gt;&lt;br /&gt;        return mark_safe(commentSoup)&lt;br /&gt;&lt;br /&gt;    except:&lt;br /&gt;        return value&lt;br /&gt;&lt;br /&gt;register.filter('tocode', tocode)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is how it works: You pull a feed from, for example, blogger, and look for PRE tags, assuming that there is something interesting (like a code snippet) inside.  After discovering that Pygments' guess_lexer has a hard time identifying most of the snippets I feed it, I decided to make it possible to explicitly specify the PRE content type.  I do this by tagging the PRE element with a class name.  In this case, I use the class name verbatim to call the get_lexer_by_name method.  So this...&lt;br /&gt;&lt;br /&gt;&amp;lt;pre class="python" &amp;gt;&lt;br /&gt;&lt;br /&gt;...will look up the python lexer and &lt;br /&gt;&lt;br /&gt;&amp;lt;pre class="php" &amp;gt;...&lt;br /&gt;&lt;br /&gt;will look up the php lexer.  &lt;br /&gt;&lt;br /&gt;The PHP lexer is very disappointing actually. &lt;br /&gt;&lt;br /&gt;Originally, I set the code to use the TextLexer in the event that PRE class attribute was not present, but this was boring.  I found that the python lexer produces more appealing results for almost all snippets, so now I'm using it as the default when the PRE attribute is not specified.  Of course, not all content will be python lexerable, so in the case of exception I fail over to the TextLexer.  The exception handling chain is a bit ugly but it gets the job done.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6734581596553603291?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6734581596553603291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6734581596553603291' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6734581596553603291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6734581596553603291'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/10/generating-html-color-formatted-ouput.html' title='Generating HTML color syntax highlighting from PRE tag'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1480750972512115722</id><published>2009-10-08T11:02:00.000-07:00</published><updated>2010-04-12T07:07:20.627-07:00</updated><title type='text'>Common git operations</title><content type='html'>Clone repository via ssh&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git clone dvenable@dvenable:~/git/python&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Show files that have changed:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git status&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;See all changes to a file:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git diff HEAD^ HEAD filename&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;See changes for a particular commit:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git show HEAD&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Show commit log for a particular file:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git log filename.py&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Show diff for all changes since branch master was created:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git diff master index.html&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1480750972512115722?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1480750972512115722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1480750972512115722' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1480750972512115722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1480750972512115722'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/10/common-git-operations.html' title='Common git operations'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6494856486880425338</id><published>2009-09-18T06:05:00.000-07:00</published><updated>2009-09-18T06:46:58.966-07:00</updated><title type='text'>Ignite Tulsa</title><content type='html'>Last night's Ignite Tulsa event was a blast.  The beer was cold, the first one was free, and the talks were often amusing.  &lt;br /&gt;&lt;br /&gt;The best presentation had to be "If someone gives you roses you should be pissed off" by Matthew Galloway.  I follow Galloway on twitter, but, as one not twitter obsessed, haven't really paid too much attention to him before.  I simply knew him as the guy who had T-Shirts made up that said, "I'm following @mattgalloway #supergenius". &lt;br /&gt;&lt;br /&gt;Well a super genius he is, or if that's overstating it, he is at least a super dynamic speaker.  His observations, from roses to Harley Davidson motorcycles, were poignant and so damn true.  The point of his five minute twenty slide rant: Have an original thought already.&lt;br /&gt;&lt;br /&gt;Hopefully he'll post his slide deck or a video will be made available. &lt;br /&gt;&lt;br /&gt;I also want to give props to my former colleague and fellow entrepreneur Geoffrey Simpson.  His presentation "Challenging Yourself" was a real inspiration.  Geoff is always trying new things, and presenting to crowd that size might have been one of those first steps he described. His conviction, energy, and positive message definitely won over the crowd.&lt;br /&gt;&lt;br /&gt;There were other notable presentations, too many to mention.   Here's a last one: &lt;a href="http://twitter.com/OKLibrarian"&gt;@OKLibrarian&lt;/a&gt; was hilarious.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6494856486880425338?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6494856486880425338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6494856486880425338' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6494856486880425338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6494856486880425338'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/09/ignite-tulsa.html' title='Ignite Tulsa'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-5670463342940167246</id><published>2009-08-21T13:38:00.000-07:00</published><updated>2009-10-07T09:36:16.760-07:00</updated><title type='text'>Verified By Visa</title><content type='html'>I've been studying Verified By Visa from the Issuer perspective for an upcoming project.  You can can get an official Visa overview by reading this &lt;a href="https://partnernetwork.visa.com/vpn/global/retrieve_document.do?documentRetrievalId=119"&gt;document&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Verified By Visa is more-or-less the brand name for the 3-D Secure service.  3-D stands for "Three Domain", referring to the three parties (Visa calls them domains) that provide the software that comprise the service.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Issuer Domain&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Implementor&lt;/span&gt;: Card holder account; Card issuer or processor&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Servers&lt;/span&gt;: Access Control Server, Authentication Enrollment Server (or pages)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Interoperability Domain&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Implementor&lt;/span&gt;: Visa&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Servers&lt;/span&gt;: Visa Directory Server, Authentication Server&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Acquirer Domain&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Implementor&lt;/span&gt;: Merchant&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Servers&lt;/span&gt;: Web Server fitted with Merchant Server Plug-in&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The issuer implementation is a relatively straightforward secure HTTPS web service.  It is even possible (and permitted) to use a single web server instance to fulfill the roles of both Access Control Server and Authentication Enrollment Server.  The Issuer server accepts requests from merchant web pages via web requests sent AJAX style and makes requests of Visa's Interoperability Domain servers.  All communication is done using a straightforward XML protocol.  &lt;br /&gt;&lt;br /&gt;It's quite the network dance that goes on between all of the players.  Visa apparently distributes a JavaScript library to each merchant for use on their web sites that abstracts the details of the interaction for them, hiding the complexities of the communication to and from the Issuer and Visa servers.&lt;br /&gt;&lt;br /&gt;I created a nice diagram that details the communication flow between the 3-D parties, but I probably shouldn't publish it. Ask me if you've got questions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-5670463342940167246?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/5670463342940167246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=5670463342940167246' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5670463342940167246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5670463342940167246'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/08/verified-by-visa.html' title='Verified By Visa'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-5508896098261308750</id><published>2009-07-22T13:38:00.000-07:00</published><updated>2009-07-22T13:47:14.182-07:00</updated><title type='text'>cx_Oracle on Ubuntu 9.04 64 bit</title><content type='html'>I had a heck of a time getting cx_Oracle for 64 bit. Using the 32 bit version didn't work either, possibly due to the ultimate problem that I eventually fixed locally. &lt;br /&gt;&lt;br /&gt;Compounding the problem: Sourceforge was buggy as hell today and I couldn't download anything due to excessive redirects. What's up with Sourceforge?  &lt;br /&gt;&lt;br /&gt;Finally found the package here:&lt;br /&gt;&lt;br /&gt;http://rpm.pbone.net/index.php3/stat/6/idpl/12200190&lt;br /&gt;&lt;br /&gt;After installing, still no dice.  Importing cx_Oracle failed with a message saying unable to locate the package.  A search of my directories showed that the RPM dropped my site-package in the wrong location, at least wrong for Ubuntu 9.04.  This fixed it:&lt;br /&gt;&lt;br /&gt;sudo cp /usr/lib/python2.6/site-packages/cx_Oracle-5.0.1-py2.6.egg-info /var/lib/python-support/python2.6&lt;br /&gt;sudo cp /usr/lib/python2.6/site-packages/cx_Oracle.so /var/lib/python-support/python2.6&lt;br /&gt;&lt;br /&gt;/var/lib instead of /usr/lib... wtf&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-5508896098261308750?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/5508896098261308750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=5508896098261308750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5508896098261308750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5508896098261308750'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/07/cxoracle-on-ubuntu-904-64-bit.html' title='cx_Oracle on Ubuntu 9.04 64 bit'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4009326154912657552</id><published>2009-05-04T09:16:00.000-07:00</published><updated>2009-05-04T10:01:18.962-07:00</updated><title type='text'>Startup Lessons #3 - What will it take to feed the founders?</title><content type='html'>If you can afford to develop your business plan and prototype after hours and on the weekend--- while keeping your day job---do it.  &lt;br /&gt;&lt;br /&gt;If you have a little bit of startup capital, assume that you will never receive another dime. &lt;br /&gt;&lt;br /&gt;Be realistic about what it is going to take to feed your founders.  Can they live on the amount in-hand for one year?  If not, don't quit the day job. &lt;br /&gt;&lt;br /&gt;Our business was born of four founders, all of whom were fairly mature in their careers.  It felt like we were making big sacrifices by paying ourselves approximately 60% of our former incomes.  Still---the combined amount required was considerable.  With what we raised we could have paid two of the founders full-time salaries for a year.  But we all went in full-time, leaving us with only 6 months running room.  It wasn't enough.  &lt;br /&gt;&lt;br /&gt;Six more months would have afforded us the opportunity to complete a pilot we began at a financial institution---a pilot with great promise. &lt;br /&gt;&lt;br /&gt;So why did we decide the four founders should quit their day jobs up front?  A number of reasons, including a strong belief that, to make the most of our combined energies, we must all be 100% committed to the effort. That creativity would best flow if we could all work together in the same room.  There may have even been a "fun" factor.  All wanted in on the excitement of rapidly building something from the ground up.&lt;br /&gt;&lt;br /&gt;What is the take away? Don't let irrational exuberance into the equation. Plan for the worst.  If you can't support your founders for a year with what you have in-pocket, think hard.  Stick with the day job or find other creative ways to support yourself while you build the company.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4009326154912657552?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4009326154912657552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4009326154912657552' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4009326154912657552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4009326154912657552'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/05/startup-lessons-1-get-real-about-number.html' title='Startup Lessons #3 - What will it take to feed the founders?'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4420247558281219803</id><published>2009-04-28T09:26:00.000-07:00</published><updated>2009-10-28T14:10:30.195-07:00</updated><title type='text'>Correcting VIM indention, Python</title><content type='html'>First off, get your VIM editor up to speed.  &lt;br /&gt;&lt;br /&gt;http://henry.precheur.org/2008/4/18/Indenting_Python_with_VIM.html&lt;br /&gt;&lt;br /&gt;Check that your filetype and settings are correct...&lt;br /&gt;&lt;br /&gt;&lt;pre class="bash"&gt;&lt;br /&gt;:filetype&lt;br /&gt;&lt;br /&gt;filetype detection:ON  plugin:ON  indent:ON                   1,0-1         Top&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now issue the magic VIM command to re-tab the entire file. &lt;br /&gt;&lt;br /&gt;&lt;pre class="bash"&gt;&lt;br /&gt;gg=G&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Or here's an alternative that converts all tabs to spaces&lt;br /&gt;&lt;br /&gt;&lt;pre class="bash"&gt;&lt;br /&gt;:set tabstop=4&lt;br /&gt;:set shiftwidth=4&lt;br /&gt;:set expandtab&lt;br /&gt;:retab&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4420247558281219803?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4420247558281219803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4420247558281219803' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4420247558281219803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4420247558281219803'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/04/correcting-vim-indention-python.html' title='Correcting VIM indention, Python'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-5986310395117937044</id><published>2009-04-27T09:09:00.000-07:00</published><updated>2009-10-28T14:11:19.479-07:00</updated><title type='text'>Revisiting Pyshards</title><content type='html'>So I had this idea last year after reading several white papers on database scaling techniques.  I also had about a week's time between paid projects to spend however I liked.  So I turned my ideas into pyshards, a quick and dirty horizontal database partitioning library.  At the end of that week, I published my effort on Google Code for a number of reasons:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;  I really couldn't find a Python-based toolkit like the one I was imagining at the time, and I needed it.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;  I was looking for Python gigs and wanted to be able to easily refer hiring technologists to something I had written in Python.  (Most of my previous work had been written in JAVA or C++, or could not be made public.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;  After years of using great free and open source, I was ready to give something back.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;  I was curious if others would volunteer to help me build the library.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;I received a number of messages from other coders saying they were looking a tool like the one I was building and would be interested in joining the project.  But the messages were about as far as it went.  Actual participation from the outside was nill.  &lt;br /&gt;&lt;br /&gt;I went on to use pyshards in my next project, but not quite in the capacity I had originally envisioned.  I did use the tool to configure my shards and I used its distribution mechanism to evenly spread data across the many databases. I didn't end up use it for querying, as I needed something a little different.  In the following months I went on to create a new page (in the Django sub-project) that visually communicated the shard organization and remaining capacity, but that was the only new work done.&lt;br /&gt;&lt;br /&gt;Though the library was imperfect and incomplete, it certainly worked for my purposes.  I gave it little thought over the next several months.  My hands were full building a new system for the company I had started with my partners.&lt;br /&gt;&lt;br /&gt;Jump ahead to PyCon 2009 in Chicago.  I had a few hours to kill on the last day before catching my plane and decided to attend an &lt;a href="http://us.pycon.org/2009/openspace/"&gt;OpenSpaces&lt;/a&gt; session called "Is my code Pythonic?"  I had intended to simply listen in, but when no one offered up their code for review, I volunteered. A lot of my Python code is proprietary, so I decided to offer up a file from pyshards for review, since it was public.  There was a LOT of feedback.&lt;br /&gt;&lt;br /&gt;At this point you may be wondering, what do they mean by Pythonic?  I generally understood it to mean that you should follow the Zen of Python coding principals and stick to the "pythonic" coding style.&lt;br /&gt;&lt;br /&gt;In case you missed it, the Zen of Python is always near and dear if you are working in a Python interpreter.&lt;br /&gt;&lt;br /&gt;&lt;pre class="bash"&gt;&lt;br /&gt;me@mrroboto:~$ python&lt;br /&gt;Python 2.5.2 (r252:60911, Jul 31 2008, 17:28:52) &lt;br /&gt;[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2&lt;br /&gt;Type "help", "copyright", "credits" or "license" for more information.&lt;br /&gt;&gt;&gt;&gt; import this&lt;br /&gt;The Zen of Python, by Tim Peters&lt;br /&gt;&lt;br /&gt;Beautiful is better than ugly.&lt;br /&gt;Explicit is better than implicit.&lt;br /&gt;Simple is better than complex.&lt;br /&gt;Complex is better than complicated.&lt;br /&gt;Flat is better than nested.&lt;br /&gt;Sparse is better than dense.&lt;br /&gt;Readability counts.&lt;br /&gt;Special cases aren't special enough to break the rules.&lt;br /&gt;Although practicality beats purity.&lt;br /&gt;Errors should never pass silently.&lt;br /&gt;Unless explicitly silenced.&lt;br /&gt;In the face of ambiguity, refuse the temptation to guess.&lt;br /&gt;There should be one-- and preferably only one --obvious way to do it.&lt;br /&gt;Although that way may not be obvious at first unless you're Dutch.&lt;br /&gt;Now is better than never.&lt;br /&gt;Although never is often better than *right* now.&lt;br /&gt;If the implementation is hard to explain, it's a bad idea.&lt;br /&gt;If the implementation is easy to explain, it may be a good idea.&lt;br /&gt;Namespaces are one honking great idea -- let's do more of those!&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So that takes care of the Zen, but what is the Pythonic coding style?  There are lots of opinions, but in general it is whatever the core developers and expert users say it is, and that evolves over time even as the fabric of the community evolves.&lt;br /&gt;&lt;br /&gt;Jump to the present.  This morning I'm finally sitting down to take a good look at the patch that Jack Diederich submitted as well as the notes I took while discussing the code with Moshe Zadka.  And as I bring the project back up for testing, I remember that the setup and configuration steps were very incomplete.  Okay Devin, quit blogging and get to work on it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-5986310395117937044?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/5986310395117937044/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=5986310395117937044' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5986310395117937044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5986310395117937044'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/04/revisiting-pyshards.html' title='Revisiting Pyshards'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6673223482632744565</id><published>2009-04-24T20:46:00.000-07:00</published><updated>2009-04-25T07:48:24.310-07:00</updated><title type='text'>Startup Lessons #2 - It takes a customer</title><content type='html'>There are startups and then there are startups.  We were never going to be a "web-based" company.  We had decided to use web-centric technology to address specific enterprise problems, so ultimately we would be an enterprise software company.  The problem we set out to solve was summed up by one angel like this, "Everybody knows and understands that data behind the firewall is a mess."  We hoped to fix that.&lt;br /&gt;&lt;br /&gt;My partners worked on a number of large telco projects that ultimately failed, and for a variety of reasons.  We understand what the corporation is left with after the legion of offshore programmers and consultants leave.  We've watched the systems go live only to then crush under the weight of massive data.  We got it that no matter how good the user interfaces, reports and controls seemed to be, what gets delivered somehow doesn't quite provide the value imagined months or years before getting into the project.  There is often disappointment. &lt;br /&gt;&lt;br /&gt;We came up with a concept would make data easy to access and integrate and that would be massively scalable.  We decided to jump.  We were going to launch a startup.  &lt;br /&gt;&lt;br /&gt;But this isn't your internet startup.  There are a whole different set of problems when launching a software company that intends to sell to Fortune 1000 companies.  With a web based company, you build it, and when you are ready to go, you make the site public.  You are deployed.  Typically the web startup's next problem is that no one shows for the party.  You've got a whole different set of problems.  &lt;br /&gt;&lt;br /&gt;But for enterprise software, you have to build it, test it and then deploy it. That takes time---time to not only build the software, but to decide on a target market, to build customer relationships, to persuade someone at the company to let you in the door.  It takes time to see through the initial deployments, to make it work in the real word, to seal a deal or two.  &lt;br /&gt;&lt;br /&gt;All of this comes out as you work through the business plan; you realize that it is going to take big money, bigger than you originally imagined, to make it through to those first customers.  It's going to take VC money.  It seemed to us, at the time, to be the the only way forward.&lt;br /&gt;&lt;br /&gt;But there is a chicken and egg problem:  The VCs won't give you the time of day until you have those first customers.  Don't kid yourself into believing anything else.  Seriously.  This is not the late nineties and no one is lining up to throw money at every clever software idea.  I swear.&lt;br /&gt;&lt;br /&gt;Our team has a combined 50 years of experience in the telco space.  We have a salesman with a proven track record, a versatile product manager, a data integration specialist with a knack for people, and a software architect.  We knew we could build it and had good long-standing relationships in our space.  The combination of our ideas, our relationships, and our technology gave us confidence that we would be able to get our product deployed and eventually sold.  The VCs and angels liked hearing this, but they asked, what about the customer?  &lt;br /&gt;&lt;br /&gt;We know about big problems at Verizon and ATT, we told them.  Are you in talks with them?  Well, not them specifically, but we have talked to a number of other interested parties.  You see, that's why we need your money.  We need it to see us through until the software is mature enough and while we work up the relationship hierarchy looking for the best champion within these companies.   &lt;br /&gt;&lt;br /&gt;That's when they tell us to come back once we're deployed at a customer site.&lt;br /&gt;&lt;br /&gt;Using our combined efforts we were able to raise some initial money.  It wasn't much compared to what it would take to keep our team working full-time for a year (I'll get to this in another post), but it was a start and it gave us hope.  We were able to take advantage of a government program to secure matching seed funds.  But additional funding did not come as quickly as hoped and our rope grew shorter and shorter. &lt;br /&gt;&lt;br /&gt;I built the software while my partners worked every possible existing relationship. The feedback was always positive.  Yes, they really liked our technology.  Yes, they wanted to work with us.  Yes.  Yes.  Yes.  By February we had developed a small sales pipeline, but we were out of money.   With no customer, there could be no investment.  With no investment, where does this leave the company?  &lt;br /&gt;&lt;br /&gt;I have omitted the fact, thus far, that the economy tanked during this our first 10 months.  I suspect that had it not, we would have secured funding from one or more of the angels we were courting.  There is of course no way to really know that.&lt;br /&gt;&lt;br /&gt;At this point my partners are looking for services work.  They will eventually find themselves engaged on location with one of our company's target customers. At that time, they will look for problems that our software, or new software, can solve.  It may be that they'll learn of new problems that require a completely different solution, but once they find it, they'll be in a great place to recommend a software solution.  They will have a technology foundation---that they own---that can be adapted to solve a number or data classification, access, performance and integration problems.  They will present their ideas and have a much easier time of getting it deployed than they would if they were coming in from the outside.  &lt;br /&gt;&lt;br /&gt;This solves a number of problems.  They will be able to articulate clearly the specific problem to the next investors, which was a bit of a problem during the first go-round.  (Clearly they won't be hired by a client unless there is a real problem to solve in the first place!)  They will be getting paid for their services work, eliminating the need to use investment to pay their salaries.  And most importantly, they will be engaged with a real-world CUSTOMER.&lt;br /&gt;&lt;br /&gt;Hindsight really is 20/20.  We probably should have gone this route on month one instead of month ten.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6673223482632744565?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6673223482632744565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6673223482632744565' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6673223482632744565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6673223482632744565'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/04/startup-lessons-2-it-takes-customer.html' title='Startup Lessons #2 - It takes a customer'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-1286079571883843386</id><published>2009-04-15T08:37:00.000-07:00</published><updated>2009-04-20T08:00:34.317-07:00</updated><title type='text'>Startup Lessons #1 - The Valley of Death</title><content type='html'>If nothing else I've gained considerable insight into the startup process during these last 10 months of chasing the dream.  The lessons are abundant.  &lt;br /&gt;&lt;br /&gt;You've heard it said that it's all about the journey, not the destination.  Well, not when you are a startup.  The destination is everything.&lt;br /&gt;&lt;br /&gt;But there is much to be said about the journey as well.  If you are an entrepreneur and thinking of going off on your own, you won't find a lot of war stories.  I imagine that those who succeed guard their formula for success and those who don't prefer to pretend that nothing happened.  The way I see it we've neither failed nor succeeded at this point, so why not reflect on a few of the lessons learned?&lt;br /&gt;&lt;br /&gt;Personally,the journey has been both rewarding and costly.  There were a lot of great experiences.  I met fellow entrepreneurs.  I learned about what it takes to look someone in the eye and ask them for money.  I was able to practice the art of giving presentations to Fortune 1000 CTOs and VPs, and of course, I was able to build a substantial---though incomplete---enterprise software system using some of my favorite technologies. And there is so much more---  consensus building when working with partners, learning to recognize when you are self-deluding, finding the energy to take action on the days when it seems there is no hope.&lt;br /&gt;&lt;br /&gt;I probably wouldn't be blogging about this today if everything with the business had gone as planned.  Friends and former co-workers keep asking me, "Is the company dead?"  Well, no.  But it is true that we're not where we had hoped to be at this point, that's for sure.  &lt;br /&gt;&lt;br /&gt;We recently held a second meeting with an Oklahoma-based VC and he said it best,"You're in the valley of death," a chasm between the initial seed funding and a substantial VC round.  It's a place where companies who have burned through their initial funding but have yet to make it to revenue reside.  Word to the wise: A substantial revenue generating customer relationship is paramount; this must happen before any serious investment consideration will be given to you by a venture fund.&lt;br /&gt;&lt;br /&gt;If you go back and read our business plan, at this moment in time we should have a development staff, a beta release, and we should be engaged with at least two paid pilots. But that didn't happen and for a lot of reasons. So what went wrong and is there any way to turn things around now?  I'll reflect and blog on it over the next several weeks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-1286079571883843386?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/1286079571883843386/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=1286079571883843386' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1286079571883843386'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/1286079571883843386'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/04/startup-lessons-1-valley-of-death.html' title='Startup Lessons #1 - The Valley of Death'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4768393026167778891</id><published>2009-04-15T06:34:00.000-07:00</published><updated>2009-04-18T06:29:31.448-07:00</updated><title type='text'>A List</title><content type='html'>So many things are going on right now.  Where to begin?  Here is a list of things that I either need or want to do in no particular order.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Blog about the startup experience&lt;br /&gt;&lt;li&gt;Find gainful employment&lt;br /&gt;&lt;li&gt;Find the time to contribute to Catherine Devlin's sqlpython project&lt;br /&gt;&lt;li&gt;Find the time to test the diff that Jack Diederich contributed to the pyshards project, and then refactor everything else&lt;br /&gt;&lt;li&gt;Take my tax filing to the post office&lt;br /&gt;&lt;li&gt;Evaluate plone, drupal, wordpress and...&lt;br /&gt;&lt;li&gt;Revamp my home page (a simple resume currently)&lt;br /&gt;&lt;li&gt;Figure out what I want to be when I grow up&lt;br /&gt;&lt;li&gt;Find the time to finish recording a new electronica song I started writing a few weeks ago&lt;br /&gt;&lt;li&gt;Keep working on my contract job---the only item in here that pays---but without getting so buried in it that I can do nothing else&lt;br /&gt;&lt;li&gt;Watch out for typos or misspellings on my blog!&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4768393026167778891?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4768393026167778891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4768393026167778891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4768393026167778891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4768393026167778891'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/04/list.html' title='A List'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4121917929774737719</id><published>2009-03-29T17:51:00.000-07:00</published><updated>2009-03-29T17:53:31.009-07:00</updated><title type='text'>Brave?</title><content type='html'>I did what I suspect was a fairly brave thing at PyCon.  I attended an Open Spaced entitled "Is This Pythonic?"  No one else was willing to put their code in front of the Python core developers (Jack Diederich and Moshe Zadka), so I offered up on of the files from my PyShards project.  Now, keep in mind that I only decided that Python would be my language of Primacy about 6 months before writing the file that they reviewed.  I tend to use the common subset of programming language features so that I can hop back and forth between programming languages without making my brain explode.   Nonetheless, I wanted to see what it would take to make my code acceptable to the most pedantic of Python programmers, so I volunteered. &lt;br /&gt;&lt;br /&gt;Check out the result:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jackdied.blogspot.com/2009/03/is-this-pythonic.html"&gt;http://jackdied.blogspot.com/2009/03/is-this-pythonic.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Jack could not pythonicify the code to his satisfaction without relying on newer and trunk Python features.  At the time of his writing, he was still not satisfied with his result.  &lt;br /&gt;&lt;br /&gt;It was an interesting, if not a bit nerve racking, exercise.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4121917929774737719?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4121917929774737719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4121917929774737719' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4121917929774737719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4121917929774737719'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/03/brave.html' title='Brave?'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6628556789119228467</id><published>2009-03-22T06:07:00.001-07:00</published><updated>2009-03-22T06:47:22.003-07:00</updated><title type='text'>Django templating</title><content type='html'>One of my contacts, John, wrote me yesterday, asking for some conceptual help with the Django templating system.  I broke down template inheritance for him, using the following very simple example.  &lt;br /&gt;&lt;br /&gt;I told John...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I typically use Django's template inheritance in this way.  A base page handles most of the boiler plate stuff and then I specialize in the inherited pages.   URLs and the views (python functions) also get involved.&lt;br /&gt;&lt;br /&gt;Here's a super simple page.  (Imagine that each code snippet lives in its own file.)  This one is base.html.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;Part One&lt;br /&gt;Part Two&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I need two more things to display a page using the Django system, the URI routing expression in urls.py and a view.  (I'm sure you get this, but to be clear I just want to call out all of the parts.)&lt;br /&gt;&lt;br /&gt;The URI expression:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; (r'^base$', base_function),&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;base_function is the view function, typically defined in another file.  Something like this will display the page without really doing anything fancy with data.&lt;br /&gt;&lt;br /&gt;&lt;pre &gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def base_function(request):&lt;br /&gt;    return render_to_response("base.html")&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;From a browser, you go to /base/, and you see...&lt;br /&gt;Part One Part Two&lt;br /&gt;&lt;br /&gt;Now you want to either extend or replace a section of the template.  First, let's extend.  We modify the original template and add markers for the areas we will be extending or replacing. &lt;br /&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;{% block one %} Part One{% endblock %}&lt;br /&gt;{% block two %} Part Two{% endblock %}&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;br /&gt;Suppose you just want to just change the second block.  So you create a file called mod2.html.&lt;br /&gt;&lt;br /&gt;{% extends "base.html" %}&lt;br /&gt;{% block two %} A different thing to render in Part Two{% endblock %}&lt;br /&gt;&lt;br /&gt;You add another URL expression in urls.py.  So now it looks like...&lt;br /&gt;&lt;br /&gt; (r'^base$', base_function),&lt;br /&gt; (r'^mod2$', mod_alt_two_function),&lt;br /&gt;&lt;br /&gt;and you add a second view function...&lt;br /&gt;&lt;br /&gt;&lt;pre &gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def mod_alt_two_function(request):&lt;br /&gt;    return render_to_response("mod2.html")&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;From a browser, you go to /mod2/, and you see...&lt;br /&gt;Part One A different thing to render in Part Two&lt;br /&gt;&lt;br /&gt;A third view might replace the first and second section....&lt;br /&gt;&lt;br /&gt; (r'^base$', base_function),&lt;br /&gt; (r'^mod2$', mod_alt_two_function),&lt;br /&gt; (r'^all$', all_mod_function),&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre &gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def all_mod_function(request):&lt;br /&gt;    return render_to_response("all.html")&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;{% extends "base.html" %}&lt;br /&gt;{% block one %} Much different than &lt;br/&gt;{% endblock %}&lt;br /&gt;{% block two %} the original{% endblock %}&lt;br /&gt;&lt;br /&gt;Producing this when you hit /all/ in the browser:&lt;br /&gt;&lt;br /&gt;Much different than&lt;br /&gt;the original&lt;br /&gt;&lt;br /&gt;So that's the basics with template inheritance.  You can also just include chunks of other templates by including them right in the middle of the page.  And you can wrap the includes in logic, so that based upon the data you are passing to the template from the view function, you can make decisions about what to include.  Here is a small snippet from one of my pages that includes one of four different HTML template 'chunks' based upon the values of the variables "result.format" and "result.render_hint".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre &gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;                    {% ifequal result.format 'pipe' %}&lt;br /&gt;                        {% ifequal result.render_hint 'email' %}&lt;br /&gt;                            {% include 'email_result.html' %}&lt;br /&gt;                        {% endifequal %}&lt;br /&gt;                        {% ifnotequal result.render_hint 'email' %}&lt;br /&gt;                            {% include 'table_properties.html' %}&lt;br /&gt;                        {% endifnotequal %}&lt;br /&gt;                    {% endifequal %}&lt;br /&gt;                    {% ifequal result.format 'text' %}&lt;br /&gt;                        {% include 'text_result.html' %}&lt;br /&gt;                    {% endifequal %}                    &lt;br /&gt;                    {% ifequal result.format 'tag' %}&lt;br /&gt;                        {% include 'tag.html' %}&lt;br /&gt;                    {% endifequal %}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6628556789119228467?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6628556789119228467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6628556789119228467' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6628556789119228467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6628556789119228467'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/03/django-templating.html' title='Django templating'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-8343660400530142788</id><published>2009-01-17T13:50:00.000-08:00</published><updated>2009-01-18T14:43:21.191-08:00</updated><title type='text'>Android Pt. 3: Photo uploading</title><content type='html'>I found enough bits and pieces of code to hobble together a photo uploader.  This blog post was helpful:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;http://itp.nyu.edu/~dbo3/blog/?p=122&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Speaking of helpful, once running an Android app with the emulator, you might wonder where Log statements are going.  Standard out doesn't show them in the Eclipse editor, but you can tail them with this command:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;adb logcat *:W&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Where do I want my uploaded photos to go?  I have been thinking about writing a small appengine app which could be used for coordinating, managing, and searching for the photographs.  Maybe I'll use flickr for photo storage, at least initially.&lt;br /&gt;&lt;br /&gt;Next up I need to find the code to upload the photos to flicker.  Knowing that I will need an API key, I requested and received one from Amazon.  I had heard that that flickr uses a hybrid rest api, and sure enough, after searching around I found no pure REST interface for authenticating and uploading.&lt;br /&gt;&lt;br /&gt;I've decided to test the basic uploading steps in Python first.  Once I get it working, I'll go back and write the more verbose version using JAVA. &lt;br /&gt;&lt;br /&gt;I found that the first step in uploading is going through an authentication handshaking sequence.&lt;br /&gt;First up, grab a frob from flickr.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import md5&lt;br /&gt;import xmlrpclib&lt;br /&gt;&lt;br /&gt;uri = "http://api.flickr.com/services/xmlrpc/"&lt;br /&gt;key = YOUR_FLICKR_API_KEY&lt;br /&gt;secret = YOUR_FLICKR_SECRET&lt;br /&gt;proxy = xmlrpclib.ServerProxy( uri )&lt;br /&gt;secretstr = secret + "api_key" + key &lt;br /&gt;hexsig = md5.new( sigstr ).hexdigest()&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;resturi = "http://api.flickr.com/services/rest/?method=flickr.auth.getFrob&amp;amp;api_key="+key+"&amp;amp;api_sig="+sig&lt;br /&gt;result = proxy.flickr.auth.getFrob( {'api_key': key, 'api_sig': sig} )&lt;br /&gt;&lt;br /&gt;print result&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;At this point, I must take a break and rejoin the human race.   More on this next time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-8343660400530142788?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/8343660400530142788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=8343660400530142788' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8343660400530142788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8343660400530142788'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2009/01/android-pt-3-photo-uploading.html' title='Android Pt. 3: Photo uploading'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6185918078334709431</id><published>2008-12-29T21:49:00.000-08:00</published><updated>2008-12-29T21:57:28.151-08:00</updated><title type='text'>Android Pt. 2: Crisis averted</title><content type='html'>I made another attempt at deploying the test application, this time using the command line tool.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;me@mrroboto:~/src/android-sdk-linux_x86-1.0_r2/tools$ ./adb -d install ~/picthere.apk&lt;br /&gt;203 KB/s (12207 bytes in 0.058s)&lt;br /&gt;   pkg: /data/local/tmp/picthere.apk&lt;br /&gt;Success&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I'm not sure why I was getting the permissions problem when deploying from inside of Eclipse.&lt;br /&gt;&lt;br /&gt;But in any case, the application has been deployed to my G1 and works as expected.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6185918078334709431?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6185918078334709431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6185918078334709431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6185918078334709431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6185918078334709431'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2008/12/android-pt-2-crisis-averted.html' title='Android Pt. 2: Crisis averted'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-7403193980931660716</id><published>2008-12-29T17:57:00.000-08:00</published><updated>2008-12-29T19:49:54.580-08:00</updated><title type='text'>Android Pt. 1: Developing and deploying first steps</title><content type='html'>To get things rolling I took the Hello World app that I had initially created using the Eclipse plugin and modified it to show a couple of buttons that pop up dialogs.  Most of the code was taken and adapted from the alert dialog example programs.&lt;br /&gt;&lt;br /&gt;Everything worked out when running the program under the emulator.  My next step was to see what it would take to deploy to the G1.&lt;br /&gt;&lt;br /&gt;When I opened up the manifest.xml file in Eclipse I noticed a link that read, "Export the unsigned apk".  I clicked the link but didn't see output in the Eclipse editor, nothing to suggest that anything had happened.  But, when I checked my home directory, I did find a new .apk file. &lt;br /&gt;&lt;br /&gt;Note: If you right-click your project in the Eclipse package view you will find a menu item under Android tools that performs the same export function.&lt;br /&gt;&lt;br /&gt;According to &lt;a href="http://code.google.com/android/devel/sign-publish.html"&gt;Google's documentation&lt;/a&gt;, my next step was to sign the apk.  Since I'm only testing a deployment to my personal phone, I was hoping that this would be fairly painless: I didn't want to mess around with the details of key generation right then.&lt;br /&gt;&lt;br /&gt;I read that there is a debug.keystore that Eclipse uses when automatically signing debug builds for deployment to the emulator.  I hoped I would be able to skip the keytool step because of this and use the same key generated by Eclipse.  Skipping to the jar signing step, I ran the following.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;jarsigner -verbose -keystore ~/.android/debug.keystore picthere.apk  PictHere&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When prompted for a password, I used the android default which is "android" according to this &lt;a href="http://www.devx.com/wireless/Article/39972/1954"&gt;page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;me@mrroboto:~$ jarsigner -verbose -keystore ~/.android/debug.keystore picthere.apk  PictHere&lt;br /&gt;Enter Passphrase for keystore: android&lt;br /&gt;jarsigner: Certificate chain not found for: PictHere.  PictHere must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Whoops.  Wrong alias for the last argument. After correcting, all worked as expected.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;me@mrroboto:~$ jarsigner -verbose -keystore ~/.android/debug.keystore picthere.apk  androiddebugkey&lt;br /&gt;Enter Passphrase for keystore: android&lt;br /&gt;  adding: META-INF/MANIFEST.MF&lt;br /&gt;  adding: META-INF/ANDROIDD.SF&lt;br /&gt;  adding: META-INF/ANDROIDD.RSA&lt;br /&gt; signing: res/drawable/alert_dialog_icon.png&lt;br /&gt; signing: res/drawable/icon.png&lt;br /&gt; signing: res/layout/main.xml&lt;br /&gt; signing: AndroidManifest.xml&lt;br /&gt; signing: resources.arsc&lt;br /&gt; signing: classes.dex&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I verified that the apk (actually a jar file) had been signed as suggested by &lt;a href="http://code.google.com/android/devel/sign-publish.html"&gt;Google&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I had a bit of a hiccup during the next step: using DDMS to deploy the app to the actual device. &lt;br /&gt;&lt;br /&gt;There is a DDMS perspective in Eclipse that is really very, very nice.  Unfortunately, after plugging the G1 into my computer via USB, the emulator showed up and not my actual device.  A number of posts suggested that the "Unknown Sources" checkbox must be enabled on the G1 (found under Settings/Applications).  After checking the box, I plugged the G1 back in and restarted Eclipse, but no device listed---still just the emulator.&lt;br /&gt;&lt;br /&gt;I decided to try it from the command line:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;me@mrroboto:~/src/android-sdk-linux_x86-1.0_r2/tools$ ./adb devices&lt;br /&gt;List of devices attached&lt;br /&gt;emulator-5554    device&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Nope...nothing there but the emulator.&lt;br /&gt;&lt;br /&gt;This &lt;a href="http://androidcommunity.com/forums/f4/how-to-install-apps-using-adb-4482/"&gt;page&lt;/a&gt; suggested that I add udev rules.   Made sense...need to give the USB device the right permissions.  (I probably should have mentioned that I'm developing on an Ubuntu box.)&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;If you're developing on Ubuntu Linux, you need to add a rules file:&lt;ol style="list-style-type: decimal;"&gt;&lt;li&gt;Login as root and create this file: /etc/udev/rules.d/50-android.rules. For Gusty/Hardy, edit the file to read:&lt;br /&gt;SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"&lt;br /&gt;For Dapper, edit the file to read:&lt;br /&gt;SUBSYSTEM=="usb_device", SYSFS{idVendor}=="0bb4", MODE="0666"&lt;/li&gt;&lt;li&gt;Now execute:&lt;br /&gt;chmod a+rx /etc/udev/rules.d/50-android.rules&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After unplugging and re-plugging the G1, it showed up for the party...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;me@mrroboto:~/src/android-sdk-linux_x86-1.0_r2/tools$ ./adb devices&lt;br /&gt;List of devices attached&lt;br /&gt;emulator-5554    device&lt;br /&gt;HT849GZ16642    device&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;At this point I was confident that I would be able to see the device in the DDMS perspective in Eclipse.  Sure enough, it was there.&lt;br /&gt;&lt;br /&gt;But sadly, when I chose the "push file to device" and selected my apk, I got the following error:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;[2008-12-29 21:35:22 - ddms]transfer error: Read-only file system&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Could it be that I am not going to be able to copy my app directly to the phone?  Apparently this is the reason I should have picked up the Android Dev Phone,  at least according to &lt;a href="http://www.itpro.co.uk/609015/google-to-sell-unlocked-g1-android-phone-for-developers"&gt;this post&lt;/a&gt;, which states that the Dev Phone is the same as the G1 but "there are no software restrictions on the device, users can directly load their own applications and test code straight to the unit rather than just relying on emulators to test code." &lt;br /&gt;&lt;br /&gt;We shall see...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-7403193980931660716?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/7403193980931660716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=7403193980931660716' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7403193980931660716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/7403193980931660716'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2008/12/android-pt-1-developing-and-deploying.html' title='Android Pt. 1: Developing and deploying first steps'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-2999006929312897382</id><published>2008-12-29T12:05:00.000-08:00</published><updated>2008-12-29T12:10:32.729-08:00</updated><title type='text'>Developing for the G1</title><content type='html'>I received a G1 for Christmas and can't resist the urge to write my first Android application.  I'll share my experience here.&lt;br /&gt;&lt;br /&gt;So far I've downloaded the SDK, installed the Eclipse plugin, wrote my first Hello World application, and examined many of the sample applications that come with the SDK.  The framework is quite simple and elegant.  &lt;br /&gt;&lt;br /&gt;My next step:  try out the deployment process.  My simple program runs fine under the Emulator, but how difficult will it be to package and deploy it to my phone?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-2999006929312897382?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/2999006929312897382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=2999006929312897382' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2999006929312897382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2999006929312897382'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2008/12/developing-for-g1.html' title='Developing for the G1'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4217618804306362734</id><published>2008-11-09T20:03:00.000-08:00</published><updated>2008-11-09T20:13:33.061-08:00</updated><title type='text'>Crap.  Gmail IMAP doesn't support searching by header Message-ID</title><content type='html'>I just spent the last hour trying to figure out why my IMAP query is failing.  I'm testing an IMAP integration with gmail.  Here is my query:&lt;br /&gt;&lt;br /&gt;&gt;&gt;&gt; type, data = mail.search(None, '(HEADER Message-ID "&lt;799d9ef60811090712j14c90d46hf9939af135dc5a19@mail.gmail.com&gt;")')&lt;br /&gt;&gt;&gt;&gt; data&lt;br /&gt;['']&lt;br /&gt;&lt;br /&gt;I should have mentioned that I'm using python IMAPLIB.&lt;br /&gt;&lt;br /&gt;Even though the message-id is valid (there is a message with this ID), nothing is returned.  Why?  It's just not supported.  From google:&lt;br /&gt;&lt;br /&gt;http://mail.google.com/support/bin/answer.py?answer=78761&amp;amp;topic=12762&amp;amp;disablechatbrowsercheck=1&lt;br /&gt;&lt;div class="answer_heading"&gt;   &lt;h2 class="answer_title"&gt;Does Gmail support all IMAP features?&lt;/h2&gt;    &lt;/div&gt;    &lt;p&gt;Gmail IMAP is a fairly complete implementation of IMAP, but the following features are currently unsupported:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;\Answered and \Recent flags on messages.&lt;/li&gt;&lt;li&gt;Substring search. All searches are assumed to be words.&lt;/li&gt;&lt;li style="font-weight: bold;"&gt;Searching arbitrary headers. Only some headers are available for searches: From/CC/BCC/To/Subject.&lt;/li&gt;&lt;li&gt;There is no SIEVE interface to Gmail filters.&lt;/li&gt;&lt;li&gt;Only plain-text LOGIN over SSL tunneled connections are supported.&lt;/li&gt;&lt;/ul&gt;Yep, that's pretty much the feature I needed.  Poop!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4217618804306362734?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4217618804306362734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4217618804306362734' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4217618804306362734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4217618804306362734'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2008/11/crap-gmail-imap-doesnt-support.html' title='Crap.  Gmail IMAP doesn&apos;t support searching by header Message-ID'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-5888656728546402673</id><published>2008-08-17T03:36:00.000-07:00</published><updated>2009-04-14T07:13:05.643-07:00</updated><title type='text'>The other Devin Venable</title><content type='html'>The Internet is a lot like your brain in that it remembers a great deal of your past.  That goofy question you asked another developer back in 1998 via a mailing list---a copy is still floating around on the net.  Or what about that videographer friend who asks for your help on a project? Do you really want the  world to see you through the prism of a music video on youtube?  How about the online petition you signed when you were all worked up over a political issue?&lt;br /&gt;&lt;br /&gt;Unlike your brain's recollection of that great moment twenty years ago, degraded and made fuzzy over time, the internet can quote your words verbatim.  Like your brain, some memories will be lost---or buried so deep that they will never resurface.&lt;br /&gt;&lt;br /&gt;The Internet is different in that it may have false memories about you. As a brain, it has more in common with the Star Trek Borg than one belonging to a human.  This is the collective memory of millions.  Fortunately, millions are not interested in you personally---unless you are Paris Hilton.  But what about those who do write about you?  And if something is attributed to you, is it the &lt;span style="font-style: italic;"&gt;right&lt;/span&gt; you?&lt;br /&gt;&lt;br /&gt;For the first several years on the Internet, I was the only Devin Venable around---as far as I could tell. Just as I had convinced myself that my name was one of a kind, a high school kid popped up, posting things that were sensible for a kid his age.&lt;br /&gt;&lt;br /&gt;I'm sure as he posted that the last thing on his mind was keeping up &lt;span style="font-style: italic;"&gt;my&lt;/span&gt; professional image on the net.&lt;br /&gt;&lt;br /&gt;If your name is John Smith or David Lee, you don't have to worry about this.  You are granted a certain anonymity because so many share your...John Doe.&lt;br /&gt;&lt;br /&gt;So this other Devin is still around.  He is in his twenties now.  How do I know this?  Because he talks about himself on sites like bebo and Facebook.  I know a lot about him.   I know that he likes to wear New Era baseball hats, listen to rap music, and---not that I wanted to know---that he wears boxers instead of briefs.&lt;br /&gt;&lt;br /&gt;Then again, I really don't know him at all.  I can't even be sure that he is &lt;span style="font-weight: bold;"&gt;one&lt;/span&gt; other person.  I don't know anything other than the public details that he (or they or &lt;span style="font-style: italic;"&gt;someone&lt;/span&gt;) is projecting on the net.  Will he/she/it/they be pleased with the picture they have painted of Devin Venable in ten years?&lt;br /&gt;&lt;br /&gt;This gets me to thinking about metadata.  Devin Venable is a very distinctive attribute (or tag). But it's not a particularly useful attribute for grouping.  Here are some seemingly common attributes of the members of this group (based upon what I know of the Devins on the Internet): [human, male, American, white].  This isn't very specific and, as the name Devin is sometimes given to females, non-whites, and non-Americans, the only truley unique attribute is that we're all human.&lt;br /&gt;&lt;br /&gt;Name your cat Devin Venable and that goes out the window as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-5888656728546402673?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/5888656728546402673/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=5888656728546402673' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5888656728546402673'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5888656728546402673'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2008/08/other-devin-venable.html' title='The other Devin Venable'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-8162235671084547876</id><published>2008-06-11T06:16:00.000-07:00</published><updated>2008-08-16T07:55:11.620-07:00</updated><title type='text'>Jacob Kaplan-Moss In Tulsa</title><content type='html'>Last night Jacob Kaplan-Moss came to speak at the Tulsa Python User's Group meeting for June.  He is one of Django's founders and one of the pair of Django's Benevolent Dictators for Life, the other being Adrian Holovaty.&lt;br /&gt;&lt;br /&gt;Jacob gave a little background on the Django project and talked about the upcoming 1.0 release.  He gave a date for the release, a news flash that he had yet to announced on the user group lists.  I think he said September, but you probably ought to check the mailing lists to get the real dope.&lt;br /&gt;&lt;br /&gt;Most interesting comments:&lt;br /&gt;&lt;br /&gt;He called Kent Beck's unit test approach either "crap" or "bullshit"---I can't recall the exact term, saying that his problem with it was sitting down to design tests before  writing functions, and testing for inputs that you will never realistically be pushing into the functions.  (Hopefully I paraphrased him correctly here.)  The gist of his point was the suggestion that the programmer should be trusted to do the right thing. &lt;br /&gt;&lt;br /&gt;Jacob also told us that he was a surprised as anyone when Google announced that AppEngine was Django based (or inspired).  Google had approached him several months before to discuss "something" but the conversation didn't happen because Jacob wouldn't sign an NDA.&lt;br /&gt;&lt;br /&gt;Of course most of the conversation was about new features, but you can go out and find that information yourself.&lt;br /&gt;&lt;br /&gt;After the meeting a few of us accompanied Jacob to McNellie's, a local pub, for a few beers.&lt;br /&gt;My impression was that he is a reasonable, down-to-earth kind of guy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-8162235671084547876?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/8162235671084547876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=8162235671084547876' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8162235671084547876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/8162235671084547876'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2008/06/jacob-kaplan-moss-in-tulsa.html' title='Jacob Kaplan-Moss In Tulsa'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-2864934866385959895</id><published>2008-05-15T05:08:00.000-07:00</published><updated>2008-05-15T05:11:16.075-07:00</updated><title type='text'>JAVA today</title><content type='html'>(I came up with this today while reviewing source.)&lt;br /&gt;&lt;br /&gt;JAVA today: take a 40 line function, explode it into 80 objects, and call it an improvement.&lt;br /&gt;&lt;br /&gt;__&lt;br /&gt;&lt;br /&gt;JAVA is not a bad language.  But the bloat and cruft is driving me crazy. If only I could do every project in Python.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-2864934866385959895?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/2864934866385959895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=2864934866385959895' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2864934866385959895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/2864934866385959895'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2008/05/java-today.html' title='JAVA today'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-5239147757222820066</id><published>2007-12-26T20:28:00.000-08:00</published><updated>2009-10-29T08:04:47.106-07:00</updated><title type='text'>Mobile Phone Site Detection</title><content type='html'>I got a Palm Centro mobile device for Christmas and it got me to thinking about the number of potential employers/clients that might use their mobile phones to view my resume or company site online.  I've been quite happy with Google's mobile-versioned sites, like &lt;a href="http://www.google.com/calendar/m"&gt;www.google.com/calendar/m&lt;/a&gt; and decided that I'd better follow the leader.&lt;br /&gt;&lt;br /&gt;It wasn't as easy as you might think to find a good mobile-phone detection script online, at least not one that worked for the Centro.  After four failed attempts, I found this one on &lt;a href="http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/"&gt;brainhandles.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="php"&gt;&lt;br /&gt;&lt;br /&gt;&lt;?php&lt;br /&gt;&lt;br /&gt;function checkmobile()&lt;br /&gt;{&lt;br /&gt;        if(isset($_SERVER["HTTP_X_WAP_PROFILE"])) &lt;br /&gt;             return true;&lt;br /&gt;&lt;br /&gt;        if(preg_match("/iphone/i",$_SERVER["HTTP_USER_AGENT"])) &lt;br /&gt;             return false;&lt;br /&gt;&lt;br /&gt;        if(preg_match("/wap\.|\.wap/i",$_SERVER["HTTP_ACCEPT"])) &lt;br /&gt;             return true;&lt;br /&gt;&lt;br /&gt;        if(isset($_SERVER["HTTP_USER_AGENT"]))&lt;br /&gt;        {&lt;br /&gt;&lt;br /&gt;             $uamatches = array("midp", "j2me", "avant", "docomo", "novarra", "palmos", "palmsource", "240x320", "opwv", "chtml", "pda", "windows\ ce", "mmp\/", "blackberry", "mib\/", "symbian", "wireless", "nokia", "hand", "mobi", "phone", "cdm", "up\.b", "audio", "SIE\-", "SEC\-", "samsung", "HTC", "mot\-", "mitsu", "sagem", "sony", "alcatel", "lg", "eric", "vx", "NEC", "philips", "mmm", "xx", "panasonic", "sharp", "wap", "sch", "rover", "pocket", "benq", "java", "pt", "pg", "vox", "amoi", "bird", "compal", "kg", "voda", "sany", "kdd", "dbt", "sendo", "sgh", "gradi", "jb", "\d\d\di", "moto");&lt;br /&gt;&lt;br /&gt;        foreach($uamatches as $uastring)&lt;br /&gt;        {&lt;br /&gt;            if(preg_match("/".$uastring."/i",$_SERVER["HTTP_USER_AGENT"])) &lt;br /&gt;                 return true;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    return false;&lt;br /&gt;}&lt;br /&gt;#example&lt;br /&gt;if(checkmobile())&lt;br /&gt;{&lt;br /&gt;  header('Location: http://www.yoursite.com/m/index.html');&lt;br /&gt;  exit;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if(!checkmobile())&lt;br /&gt;{&lt;br /&gt;  header('Location: http://www.yoursite.com/');&lt;br /&gt;  exit;&lt;br /&gt;}&lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It's a PHP script, of course.  For my purposes, I just created an index.php file and set "DirectoryIndex index.php index.html".  The first thing the visitor hits is the php file, which either redirects to the main index.html file or the mobile version in the "m" directory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-5239147757222820066?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/5239147757222820066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=5239147757222820066' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5239147757222820066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/5239147757222820066'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2007/12/mobile-phone-site-detection.html' title='Mobile Phone Site Detection'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-6375708101573182769</id><published>2007-11-06T05:19:00.000-08:00</published><updated>2008-08-17T04:40:30.704-07:00</updated><title type='text'>Open Source Project Management</title><content type='html'>&lt;span style="font-size:180%;"&gt;Do's and Don't&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Use Open Source Judiciously &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We all know the benefits of using open source, but what are the pitfalls?  If you have been asked to build a professional, production-ready, mission-critical, customer-facing application, you probably &lt;span style="font-style: italic;"&gt;don't&lt;/span&gt; want to go bleeding edge.&lt;br /&gt;&lt;br /&gt;You need to ask yourself if the project is ready for prime-time.  Don't be fooled by a glossy, over-hyped project page.  Dig deep.  Find out&lt;br /&gt;how many people are really using the project.  Look at the mailing list archives.   Is it active enough?  Is is full of unanswered questions?  Check out the source from subversion.  Review the check-in history.  If time permits, read the code.&lt;br /&gt;&lt;br /&gt;For short-timeframe, mission-critical projects, I use what I call The Book Test. Any project for which an O'Reilly book has been written has been vetted and tested to my satisfaction.  If three or more books on the subject have been written and are available from your local bookstore, you can bet that the technology is ubiquitous. Tried and true open source projects include Linux, Apache web server, Python, PHP, and Ruby.  This litmus test will eliminate a majority of the projects you find on source forge, so this shouldn't be your only test.  But it's a good place to start.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-6375708101573182769?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/6375708101573182769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=6375708101573182769' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6375708101573182769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/6375708101573182769'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2007/11/open-source-project-management.html' title='Open Source Project Management'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4003706411436392715</id><published>2007-11-03T09:03:00.000-07:00</published><updated>2007-11-03T10:06:41.931-07:00</updated><title type='text'>Wireless Problems Upgrading Ubuntu to Gutsy</title><content type='html'>I ran into trouble this week while installing Ubuntu Gutsy on some older hardware for my five year old son Kadin.  He'd been using a prism2 based wireless card with success under older releases of Ubuntu for over a year, so I knew that the card was supported.  But after completing the fresh install, network manager couldn't find my home network.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.lockergnome.com/nexus/linux/author/matt-hartley/"&gt;Matt Hartley&lt;/a&gt; suggested that the problem was with Network Manager in this &lt;a href="http://www.lockergnome.com/nexus/linux/2007/10/18/ubuntu-gutsy-wireless-help"&gt;post&lt;/a&gt;, but I followed his recipe, winstalling wicd as a replacement, and it didn't help my situation.  Wicd had the same problems detecting my home network. &lt;br /&gt;&lt;br /&gt;ifconfig reported two interfaces for my wireless card---wifi0 and wlan0.  Some suggested blacklisting hostap_pci (and others) to remove conflicting drivers which might be confusing network manager.  The best suggestion I found early on---which didn't work for me at the time---was to install the linux-wlan-ng package.  This was the right thing to do (the needed prism2 driver is installed), but unfortunately, this didn't work either.  Perhaps some additional configuration was needed?&lt;br /&gt;&lt;br /&gt;Since, according to some, the real problem was with Network Manager, and since it was working well for us under Feisty, I decided to pin back those packages using apt.&lt;br /&gt;&lt;br /&gt;I added the following to /etc/apt/preferences:&lt;br /&gt;&lt;br /&gt;Package: *&lt;br /&gt;Pin: release a=gutsy&lt;br /&gt;Pin-Priority: 700&lt;br /&gt;&lt;br /&gt;Package: network-manager&lt;br /&gt;Pin: release a=feisty&lt;br /&gt;Pin-Priority: 800&lt;br /&gt;&lt;br /&gt;Package: network-manager-gnome&lt;br /&gt;Pin: release a=feisty&lt;br /&gt;Pin-Priority: 800&lt;br /&gt;&lt;br /&gt;Then I duped all of the repository entries in /etc/apt/sources.list and changed each "gutsy" to "feisty" so that apt can find modules in both repositories.  Then I ran:&lt;br /&gt;&lt;br /&gt;sudo apt-get install network-manager network-manager-gnome&lt;br /&gt;&lt;br /&gt;This successfully downgraded and pinned the two Network Manager packages to the versions that are available in Feisty Fawn. &lt;br /&gt;&lt;br /&gt;I was really pleased that the downgrade went so smoothly, as I've gotten trapped in dependency hell attempting similar feats in the past.  Sadly, though, my problem remained!  Perhaps Network Manager was not at fault after all.&lt;br /&gt;&lt;br /&gt;linux-wlan-ng seemed to be the right solution for my card, so I decided to build from source from the trunk.&lt;br /&gt;&lt;br /&gt;svn co svn://svn.shaftnet.org/linux-wlan-ng/trunk&lt;br /&gt;&lt;br /&gt;Then I built and installed it and followed the directions in the README to setup, which included setting values in /etc/wlan/wlan.conf.  I added my home network's SSID and changed the following entry:&lt;br /&gt;&lt;br /&gt;# for some reason, this value was set to N --- seemed wrong to me&lt;br /&gt;WLAN_SCAN=y&lt;br /&gt;&lt;br /&gt;I also added the suggested values to /etc/rc.local (for modprobing the correct driver---prism2_pci in my case).&lt;br /&gt;&lt;br /&gt;I remembered seeing wlan0 aliases under /etc/modprobe.d, so I grepped for matches and found this file:&lt;br /&gt;/etc/modprobe.d/linux-wlan-ng&lt;br /&gt;&lt;br /&gt;The contents are shown below.  The "alias wlan0 prism2_pci" line was commented so I removed the comment.&lt;br /&gt;&lt;br /&gt;# Aliases to tell insmod/modprobe which module to use when bringing up the&lt;br /&gt;# wlan0 interface.&lt;br /&gt;&lt;br /&gt;# Uncomment the line corresponding to the type of prism2 device you have.&lt;br /&gt;alias wlan0 prism2_pci&lt;br /&gt;#alias wlan0 prism2_usb&lt;br /&gt;#alias wlan0 prism2_cs&lt;br /&gt;#alias wlan0 prism2_plx&lt;br /&gt;&lt;br /&gt;# this allows network manager to manipulate the device&lt;br /&gt;options p80211 wlan_wext_write=1&lt;br /&gt;&lt;br /&gt;I rebooted and network manager was able to find my home network, as well as a number of my neighbors wireless network.  In hindsight, I wonder if, after installing  linux-wlan-ng as a package, I had just removed the comment from this file and WLAN_SCAN=Y, my troubles would have washed away?  If you are having similar problems, I would try that first before compiling the latest driver from source.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4003706411436392715?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4003706411436392715/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4003706411436392715' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4003706411436392715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4003706411436392715'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2007/11/wireless-problems-upgrading-ubuntu-to.html' title='Wireless Problems Upgrading Ubuntu to Gutsy'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-717355763821404082</id><published>2007-11-01T12:39:00.000-07:00</published><updated>2009-10-28T14:02:30.215-07:00</updated><title type='text'></title><content type='html'>I posted a question to the Wicket users group a few days ago on how to best deal with frames, in particular how to pass arguments between a tree view in one frame and a list view in another.  I didn't get any takers.&lt;br /&gt;&lt;br /&gt;I finally determined that there was no good way other than to use plain-old javascript to push values from the tree up to the parent frame, where they are dispersed to the other frames.&lt;br /&gt;&lt;br /&gt;I wanted to use LinkTree, but really didn't need most of the features other than the look and feel.  I just needed to be able to insert an onclick link that would pass a value to my parent frame.&lt;br /&gt;&lt;br /&gt;After a lot of digging I came up with a solution that worked, but seems verbose for the job I'm attempting.  My question for the reader is this:  Can you propose a more concise solution?&lt;br /&gt;&lt;br /&gt;&lt;pre class="java"&gt;&lt;br /&gt;public class CategoryTree extends LinkTree&lt;br /&gt;{&lt;br /&gt;  @Override&lt;br /&gt;  protected Component newNodeComponent(String id, IModel model)&lt;br /&gt;  {&lt;br /&gt;      return new LinkIconPanel(id, model, CategoryTree.this)&lt;br /&gt;      {&lt;br /&gt;          private static final long serialVersionUID = 1L;&lt;br /&gt;&lt;br /&gt;          protected void onNodeLinkClicked(TreeNode node, BaseTree tree, AjaxRequestTarget target)&lt;br /&gt;          {&lt;br /&gt;              super.onNodeLinkClicked(node, tree, target);&lt;br /&gt;              CategoryTree.this.onNodeLinkClicked(node, tree, target);&lt;br /&gt;          }&lt;br /&gt;       &lt;br /&gt;          protected Component newContentComponent(String componentId, BaseTree tree, IModel model)&lt;br /&gt;          {&lt;br /&gt;              Label l = new Label(componentId, model)&lt;br /&gt;              {&lt;br /&gt;                  private static final long serialVersionUID = 1L;&lt;br /&gt;               &lt;br /&gt;                  @Override&lt;br /&gt;                  protected void onComponentTag(ComponentTag tag)&lt;br /&gt;                  {&lt;br /&gt;                      super.onComponentTag(tag);&lt;br /&gt;                      tag.put("onclick", "parent.notifyViews(this.getAttribute('catalogid'))");&lt;br /&gt;                   &lt;br /&gt;                  }&lt;br /&gt;              };&lt;br /&gt;       &lt;br /&gt;              DefaultMutableTreeNode n = (DefaultMutableTreeNode)model.getObject();&lt;br /&gt;           &lt;br /&gt;              if (n.getUserObject() instanceof EcCategoryTreeNode)&lt;br /&gt;              {&lt;br /&gt;                  EcCategoryTreeNode ec = (EcCategoryTreeNode)n.getUserObject();&lt;br /&gt;                  l.add(new SimpleAttributeModifier("catalogid", "" + ec.getId()));&lt;br /&gt;              }&lt;br /&gt;           &lt;br /&gt;              return l;&lt;br /&gt;          };&lt;br /&gt;      };&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public CategoryTree(String s, TreeModel tm)&lt;br /&gt;  {&lt;br /&gt;      super(s,tm);&lt;br /&gt;      this.setLinkType(LinkType.REGULAR);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-717355763821404082?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/717355763821404082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=717355763821404082' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/717355763821404082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/717355763821404082'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2007/11/i-posted-question-to-wicket-users-group.html' title=''/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-4210042432606054942</id><published>2007-10-24T15:17:00.000-07:00</published><updated>2007-10-26T06:13:24.951-07:00</updated><title type='text'>Wicket and HTML CSS attributes</title><content type='html'>JAVA open source web frameworks are everywhere.  And the documentation is everywhere, which is not always a good thing.  Especially when what you want is to go to a &lt;span style="font-style: italic;"&gt;particular&lt;/span&gt; somewhere to find all of the documentation.  Mailing lists are great, but you may end up the first to post on your problem.  As long as you don't need to get it done---you have no problem.&lt;br /&gt;&lt;br /&gt;I didn't find a post or documentation that addressed the problem I was facing today.&lt;br /&gt;&lt;br /&gt;In this case, the task I had to complete was simple:  render an HTML table, alternating the background color for each row.  I've implemented this pattern a half dozen times before using Java Servlets, ASP, PHP, OpenLaszlo and even a Struts-like  home-grown system when working for a previous employer.  In the end, it has always come down to plain old HTML and CSS, programatically assigning one of two CSS classes to a table row.  (OpenLaszlo was an exception.)&lt;br /&gt;&lt;br /&gt;This time around I'm using Wicket.   I must admit that I'm not to crazy about heavy, rule-wielding web frameworks because they often improve on the way you accomplish big tasks, but make it exponentially more difficult to do the simple ones that don't fit nicely into their design.  Is this true of Wicket?  It's too early for me to say, but I'm certainly interested in finding the answer to that question.&lt;br /&gt;&lt;br /&gt;The early verdict: So far, Wicket seems to do a pretty decent job doing what a framework ought to do. &lt;br /&gt;&lt;br /&gt;Wicket keeps the presentation concerns separate from the model.   In practical term this means that the web stuff (javascript, CSS, HTML) is kept independent from the JAVA source.  No mixing-and-matching within a single file.  Wicket does a lot more, but I'll leave it to others to sell you on it.&lt;br /&gt;&lt;br /&gt;For a non-Wicket web app, the type of logic required to provide alternating rows is normally applied in a for loop, using mod to determine if you are dealing with an even or odd row.  In a scripting language, the whole operation takes all of two lines of code.&lt;br /&gt;&lt;br /&gt;So I set out to do the same for Wicket.  Fifteen minutes of googling and I found &lt;a href="http://cwiki.apache.org/WICKET/how-to-modify-an-attribute-on-a-html-tag.html"&gt;How to modify an attribute on a HTML tag&lt;/a&gt;.  Sounded promising, but upon reading, looked verbose.  (Must we really use a separate model and view to create a simple attribute pair?)&lt;br /&gt;&lt;br /&gt;Reading this page, it wasn't apparent how the example would lend itself to my case.  However, with some experimentation, I was able to retrofit the familiar pattern onto the Wicket frame.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   &lt;br /&gt;&amp;lt;tr wicket:id="catalog" class="unknown"&amp;gt;&lt;br /&gt;&amp;lt;td wicket:id="name"&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;&amp;lt;td wicket:id="sku"&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;&amp;lt;td wicket:id="manufacturer"&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;/tr&amp;gt;&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  ListView listview1 = new ListView("catalog",    catalogItems.getProductWindow())&lt;br /&gt;  {&lt;br /&gt;          public final String style1 = "row_light";&lt;br /&gt;          public final String style2 = "row_dark";&lt;br /&gt;       &lt;br /&gt;          protected void populateItem(ListItem item)&lt;br /&gt;          {&lt;br /&gt;              Map rec = (Map) item.getModelObject();&lt;br /&gt;           &lt;br /&gt;              item.add(new Label("name", (String)rec.get("cttm_display")));&lt;br /&gt;              item.add(new Label("sku", (String)rec.get("cttm_partnumber")));&lt;br /&gt;              item.add(new Label("manufacturer", (String)rec.get("mfg_name")));&lt;br /&gt;              ...&lt;br /&gt;           &lt;br /&gt;              if (item.getIndex() % 2 == 0)&lt;br /&gt;                  item.add(new AttributeModifier("class", new PropertyModel(this, "style1")));&lt;br /&gt;              else&lt;br /&gt;                  item.add(new AttributeModifier("class", new PropertyModel(this, "style2")));&lt;br /&gt;&lt;br /&gt;          }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I used PropertyModel to get around having to create beans to hold the two strings representing the CSS classes.  Does the reader see a better solution?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-4210042432606054942?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/4210042432606054942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=4210042432606054942' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4210042432606054942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/4210042432606054942'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2007/10/wicket-and-html-style-attributes.html' title='Wicket and HTML CSS attributes'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-3863103244770942611</id><published>2007-05-05T07:34:00.000-07:00</published><updated>2007-10-24T15:16:43.521-07:00</updated><title type='text'>Indexing and Ranking</title><content type='html'>It is not easy to get a high Google ranking.&lt;br /&gt;&lt;br /&gt;A few weeks back I revived my auction website, &lt;a href="http://www.fleahaus.com/"&gt;www.fleahaus.com&lt;/a&gt;.  I say revived because I originally developed the site a few years back. It was born, it floundered, it died a slow and agonizing death.&lt;br /&gt;&lt;br /&gt;So I got a case of the what-if-I-had-done-it-a-little-differentlies and decided to administer CPR.  For example, I initially designed the site show items by region, a feat accomplished by using subdomains.  Criagslist uses this very concept currently---based on the geographical data you submit, you see a city based portal.  For example---when I visit craigslist, I am directed to  http://tulsa.craigslist.com because I live in the Tulsa area.  My original site used the same pattern.&lt;br /&gt;&lt;br /&gt;This time around I threw out the city based portal idea and introduced a local search button.  This ultimately accomplishes the same goal---giving users a way to find items that are geographically near to them---something very important to those who want to sell items too large or heavy to ship by mail.  This gave me a change to try out Google's GeoLocate APIs.&lt;br /&gt;&lt;br /&gt;After the face-lift and new features were done, it took three weeks before Google indexed my site.  This is apparently not too bad.&lt;br /&gt;&lt;br /&gt;The delay in indexing during that three weeks was a major concern for me--- especially because I had so much trouble getting the original site indexed.    I partially attribute the failure of the original site (www.communitybuy.com for the record) to my inability to get Google to index the darn thing.&lt;br /&gt;&lt;br /&gt;I'm still not quite sure why communitybuy.com failed to make it into the index.   Perhaps because I didn't put effort into back-linking at that time?  Formatting issues? Only the crawler knows for sure.&lt;br /&gt;&lt;br /&gt;Google's webmaster tools have been beneficial this go-round.  I have been able to check crawl rates, get indexing status, and more.&lt;br /&gt;&lt;br /&gt;So one milestone met:  &lt;a href="http://www.fleahaus.com/"&gt;www.fleahaus.com&lt;/a&gt; is indexed.  Next, find a way to move up the rankings.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-3863103244770942611?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/3863103244770942611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=3863103244770942611' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3863103244770942611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/3863103244770942611'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2007/05/indexing-and-ranking.html' title='Indexing and Ranking'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19895055.post-113467608422634350</id><published>2005-12-15T07:10:00.000-08:00</published><updated>2005-12-18T20:57:18.603-08:00</updated><title type='text'>Tunneling VNC over SSH</title><content type='html'>&lt;span style="font-size:130%;"&gt;Connecting a Windows Cygwin client to a Linux SSH/VNC server across the public Internet&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are times when I need to connect to my computer at home from work, most often because I need to retrieve a file or program stored there. A common scenario is one where I can (sort of) remember the name of the file I'm after, but not its location on my home computer's hard drive. This computer is a Linux server and what I end up doing is opening a &lt;a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?ssh+1"&gt;SSH&lt;/a&gt; shell into my home box, and then I use tools running on my home machine to locate the file I'm after. Sometimes I find myself changing directories and listing files like mad until it comes up, particularly if the &lt;a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?locate+1"&gt;slocate &lt;/a&gt;database is out of date.  Once I find the file I'm after, I open a second &lt;a href="http://www.cygwin.com/"&gt;Cygwin &lt;/a&gt;shell on the client side (at work that is), and issue &lt;a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?scp+1"&gt;SCP&lt;/a&gt; to retrieve it.&lt;br /&gt;&lt;br /&gt;Sometimes I'm just not in the mood to work with shells. Recently, while in one such mood, I thought I might try perusing the files on my home machine using Gnome’s Nautilus file manager. After some fiddling around with environment variables, I did manage this via X over SSH, but the performance was dismal. I've heard people say that the X protocol is too chatty, and that you shouldn't expect good client/server performance over the Internet in most cases. I’d been advised that I would have better luck using &lt;a href="http://www.tightvnc.com/"&gt;VNC&lt;/a&gt; and so I decided to give it a try.&lt;br /&gt;&lt;br /&gt;I needed to run the VNC server on the machine whose desktop I wished to view---my home computer---a scenerio that would seem to necessitate that I poke a hole in my home firewall to let the VNC traffic through.  Nay, nay.&lt;br /&gt;&lt;br /&gt;For reasons I hope are totally obvious, only a single incoming port opens into my home network, and that's SSH port 22.  I lock this port down as tight as I can using configuration rules, of course. (Wow…even &lt;span style="font-style: italic;"&gt;admitting &lt;/span&gt;that I have an open port feels like a security risk.) Instead of exposing the VNC server's listening port to the public Internet, I preferred tunneling VNC traffic over my SSH connection.&lt;br /&gt;&lt;br /&gt;It took a few hours of research before I was able to pull this off. I’ll retrace my steps here for the benefit of others of similar need and configuration.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Client Requirements&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As I began my research, I found a lot of information on how to accomplish VNC tunneling using the Putty SSH program for Windows on the client side. I personally use Cygwin tools, am quite happy with them, and didn’t see the sense in downloading yet another SSH client (thank you very much). And so I decided to use my existing Cygwin SSH client, one of the two tools you will need to have on your Windows client box if you intend to reproduce these steps for yourself, using my cookbook recipe.&lt;br /&gt;&lt;br /&gt;The second of the two Windows programs you’ll need is a VNC client, and I suggest you use &lt;a href="http://www.tightvnc.com/"&gt;TightVNC&lt;/a&gt;.  I think you can download an executable for the viewer only, but I just &lt;a href="http://www.tightvnc.com/download.html"&gt;grabbed a download&lt;/a&gt; that included both the client and server.  I’m sure I’ll use the server on my work box at some point down the road.&lt;br /&gt;&lt;br /&gt;(By the way, if you google for “SSH VNC Tunneling” and find a lot written about setting an AllowLoopback value in a registry key for TightVNC---disregard it. It’s not needed for what we’re going to do.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Server Requirements&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You’ll need a running server that accepts SSH connections and that has VNC installed. Many modern Linux distributions install it by default, so you may already have it.&lt;br /&gt;&lt;br /&gt;1. Open a SSH shell into your remote machine. If you’ve not used VNC before, you should set a password. You’ll provide this password when opening your VNC client later on.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;[me@aldous ~]$ vncpasswd&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;Password: *****&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;Verify: *****&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;2.    Start a &lt;a href="http://www.tightvnc.com/doc/man/vncserver.1.html"&gt;vncserver&lt;/a&gt;.  You should be able to just type ‘vncserver’ and use the defaults.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;[me@aldous ~]$ vncserver&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;New 'aldous:1 (me)' desktop is aldous:1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;Starting applications specified in /home/me/.vnc/xstartup&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;Log file is /home/me/.vnc/aldous:1.log&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;3.    Use the tail command to peek at your log.  We’re interested in which port VNC will be listening on.&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;[me@aldous ~]$ tail /home/me/.vnc/aldous:1.log&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;Xvnc version 4.0 - built Oct  6 2004 08:11:33&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;Underlying X server release 60801000, The X.Org Foundation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;Thu Dec 15 09:17:00 2005&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;vncext:      VNC extension running!&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;vncext:      Listening for VNC connections on port 5901&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;vncext:      Listening for HTTP connections on port 5801&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;vncext:      created VNC server for screen 0&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We’re interested in port 5901 for this example.  That’s it for the server side of things.&lt;br /&gt;&lt;br /&gt;4. Open a new Cygwin window on your Windows client and type something like the following, replacing USERNAME with the username you use to SSH into your remote machine, replacing myhomebox.net with the IP address or DNS lookup-able name of your home box. Also replace the trailing 5901 with the port reported to you in step three (from the Listening for VNC connections… line).&lt;br /&gt;&lt;br /&gt;&lt;pre style="color: rgb(51, 51, 255);"&gt;ssh -l USERNAME myhomebox.net -L 5900:127.0.0.1:5901&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;A little explanation here is warranted.&lt;br /&gt;&lt;br /&gt;First, let’s see what the &lt;a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?ssh+1"&gt;ssh man page&lt;/a&gt; says about the –L option.&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 20px;"&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;-L [bind_address:]port:host:hostport&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-family:courier new;"&gt;          Specifies that the given port on the local (client) host is to be&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         forwarded to the given host and port on the remote side.  This&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         works by allocating a socket to listen to port on the local side,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         optionally bound to the specified bind_address.  Whenever a con-&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         nection is made to this port, the connection is forwarded over&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         the secure channel, and a connection is made to host port&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         hostport from the remote machine.  Port forwardings can also be&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         specified in the configuration file.  IPv6 addresses can be spec-&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         ified with an alternative syntax:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         [bind_address/]port/host/hostport or by enclosing the address in&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         square brackets.  Only the superuser can forward privileged&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         ports.  By default, the local port is bound in accordance with&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         the GatewayPorts setting.  However, an explicit bind_address may&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         be used to bind the connection to a specific address.  The&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         bind_address of ``localhost'' indicates that the listening port&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;         be bound for local use only, while an empty address or `*' indi-&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    cates that the port should be available from all interfaces.&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;Let's look at the command once again.&lt;br /&gt;&lt;pre style="color: rgb(51, 51, 255);"&gt;ssh -l USERNAME myhomebox.net -L 5900:127.0.0.1:5901&lt;br /&gt;&lt;/pre&gt;The first number after the –L specifier, 5900, is the port your local client will be listening on that will be forwarded across the tunnel to your remote box. 5900 is the port that the TightVNC client tries to contact when establishing a VNC connection by default, so this is a pretty good number to use. The second number, 127.0.0.1, is the address of the remote machine &lt;span style="font-style: italic;"&gt;from the perspective of the remote machine&lt;/span&gt;. Attempting to use the public IP address of your home machine, the one that you see from your client box, probably won’t work because of firewall rules, etc. I won’t get into an explanation here…just use 127.0.0.1. The third number, 5901, is the port your VNC server is listening on, on the remote machine.&lt;br /&gt;&lt;br /&gt;Note that the above SSH command will not only create your tunnel, but it will also open a SSH command shell. To prevent this, add –T and –N to your list of command arguments.&lt;br /&gt;&lt;pre style="color: rgb(51, 51, 255);"&gt;ssh -l USERNAME myhomebox.net -L 5900:127.0.0.1:5901 -T -N&lt;/pre&gt; This will disable pseudo-tty allocation and prevent you from opening a shell.  See man ssh for more information.&lt;br /&gt;&lt;br /&gt;5. Start your TightVNC viewer (Fast compression). A dialog will pop up asking you to enter the IP address of a VNC Server. Enter 127.0.0.1. You will then be prompted for the password you created for your VNC server back in step one.&lt;br /&gt;&lt;br /&gt;If all went well, you should now be looking at your remote machine’s desktop.&lt;br /&gt;&lt;br /&gt;To avoid confusion about the use of the 127.0.0.1 IP address (we gave it to the TightVNC Viewer as the VNC server's address, and to the SSH command as the host address) , let me describe the tunnel from the perspective of the VNC client. For the TightVNC viewer you specified that the VNC server was running on 127.0.0.1. In other words, you specified your localhost...the box at your physical location (a.k.a. the client). The VNC client then looked for the default port that VNC servers run on (5900) and said (or would if it could speak), “Ah ha! There is indeed a VNC server running on this same box.” But of course you fooled it. Due to the nifty SSH command and the –L option, you created a tunnel that forwarded the traffic on the 5900 port on to, through SSH, your home (or remote) machine. The VNC client was never any the wiser.&lt;br /&gt;&lt;br /&gt;Something similar happened on the remote side. The request to speak with the VNC server came out of the tunnel on the remote side and it asked (again, if machines could talk like us), “Any VNC servers around here that want to respond to a VNC client? I’m looking for one that is running here locally…it’s addressed to 127.0.0.1:5901.”&lt;br /&gt;&lt;br /&gt;The point I’m getting around to is that both the client and the server side of VNC think that they are talking to services running on their own machines. SSH is acting as a proxy on both sides of the tunnel. Pretty cool, eh?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;And if it didn’t work for you…&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Look at your vncserver log on the remote machine.  If an attempt was made and failed for any reason, you’ll read about it there.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[me@aldous ~]$ tail /home/me/.vnc/aldous:1.log&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Also make sure your problem is not with making the connection to your remote box.  You might check the secure log.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[me@aldous ~]$ tail /var/log/secure&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19895055-113467608422634350?l=devinvenable.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devinvenable.blogspot.com/feeds/113467608422634350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19895055&amp;postID=113467608422634350' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/113467608422634350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19895055/posts/default/113467608422634350'/><link rel='alternate' type='text/html' href='http://devinvenable.blogspot.com/2005/12/tunneling-vnc-over-ssh.html' title='Tunneling VNC over SSH'/><author><name>Devin Venable</name><uri>http://www.blogger.com/profile/08452642316203950662</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
