devin venable bits

FEED

Thought Stream Follows

Fri May 11 06:18:38 2012
Jquery Mobile and rubber band drag effect

brokentoe 03:40:11 PM
Best way to eliminate rubber banding of entire page on touch drag?  Want header and footer to stay fixed.

pizthewiz 03:49:56 PM
if you are using PhoneGap on iOS, it has a config option UIWebViewBounce in Cordova.plist, if not you are left to your own devices to sort out (0:


In short, if you are using JQuery mobile as a webapp only, there is not a sanctioned way to prevent fixed headers and footers from bouncing when user attempts to scroll content area past bottom or top of page.  I've tried several posted workarounds, from iscroll.js to custom css and javascript hacks.  Still looking for the perfect solution.
Tue May 1 15:47:03 2012
tag:
Thu Mar 22 20:51:32 2012
tag:
Thu Mar 15 01:40:15 2012
tag:
Thu Feb 23 16:10:13 2012
devinvenable: Testing twitter integration: http://t.co/cjPL9Usc
Mon Feb 20 02:47:11 2012
tag: graph
Sun Feb 19 20:16:46 2012
tag: xen
Wed Feb 15 17:35:59 2012
tag:
Wed Feb 15 09:41:01 2012
Badges
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.

SayAh Review Results

I'm not sure if the badge fragment will render properly within a blogger post, thus this post, which tests behavior.
Sun Feb 12 18:04:07 2012
devinvenable: http://t.co/QwRBDeMM
Wed Feb 1 17:23:56 2012
tag:
Mon Jan 30 15:23:02 2012
devinvenable: @rjpierson42 I haven't been on twitter for ages. Any new compelling reason to be here?
Sat Jan 7 22:39:49 2012
tag:
Sat Jan 7 22:36:55 2012
tag:
Tue Jan 3 02:54:17 2012
tag:
Fri Dec 16 16:08:23 2011
tag: css3
Fri Sep 30 13:37:09 2011
tag:
Tue Sep 27 02:13:28 2011
devinvenable: I almost never use twitter, but google tv app makes me want to tweet.
Wed Sep 21 08:51:55 2011
git differences between working copy and stashed copy
Shows the differences between copy and third item in the stash stack...

git diff stash@{3}

Thu Sep 15 20:59:49 2011
tag: canvas
Wed Sep 14 19:10:49 2011
tag: canvas
Wed Sep 14 18:56:51 2011
tag: svg
Tue Sep 13 21:42:22 2011
tag: svg
Mon Sep 12 08:58:23 2011
Vim search and replace from current location to end of file
Instead of searching and replacing the entire file with...

:s/old/new/g

Try inserting ".," just after the colon. This means "from current position to end of file".


:.,s/old/new/g

The comma actually specifies a range to make the substitution, from left and right of comma. For example...

:5,10s/old/new/g

...makes the substitutions on lines 5 through 10.


Fri Sep 9 16:09:57 2011
devinvenable: Notice for Tulsa .NET developers: http://t.co/VcMooxJ
Fri Sep 9 09:07:29 2011
Notice to .NET developers
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.

Meanwhile, Tulsa is flooded with .NET developers, which drives the rate .NET developers demand, downward.

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.
Sat Sep 3 17:10:48 2011
devinvenable: My fiancée does waxing and facials and she is famously good at it. http://t.co/NBgVTb8
Wed Aug 31 18:15:36 2011
tag: css
Wed Aug 31 12:40:38 2011
Vim tags
Continuing on with my exploration of Vim features I've yet to use, let's explore tags.

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.

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.

":tags" shows you your list of tags.

:tags
# TO tag FROM line in file/text
> 1 1 LongTextAnswer 8 q = LongTextAnswer()

Each time I show my :tags I get this error:

E433: No tags file.

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. I'll try installing exuberant-ctags and see what affect that has on my operation.

sudo apt-get install exuberant-ctags

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.

http://amix.dk/blog/post/19329

On a related note, you can read ctags in python:

http://code.google.com/p/python-ctags/





Wed Aug 31 07:09:38 2011
Vim Execute Mode
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?"

Take Execute Mode for example. In 10 years of Vim use, I've never tried it. Let's fix that now.

You enter Execute Mode by pressing capital Q (shift + q) when in normal mode. You'll see this at the bottom of your window.

Entering Ex mode. Type "visual" to go to Normal mode.
:

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.

:w filename

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.

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.


Tue Aug 30 19:06:11 2011
devinvenable: RT @argoneus: VimConf - Virtual conference for Vim lovers all over http://t.co/rdktSDK
Mon Aug 29 18:41:54 2011
devinvenable: Tulsa web devs: drop me a line if you are looking for a paying project.
Mon Aug 8 09:03:52 2011
Safari URL opens new window
Here's a strange quirk I encountered while working with Safari mobile: HTML anchors (<a href="http://www.blogger.com/something.html">click</a>) open a new Safari browser instance---every time.

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:

http://www.naquah.net/blog/dennis/2008/03/21/how-to-enable-single-window-mode-in-safari

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:

http://www.w3schools.com/tags/att_a_target.asp

Attribute Values
Value Description
_blank Open the linked document in a new window or tab
_self Open the linked document in the same frame as it was clicked (this is default)
_parent Open the linked document in the parent frameset
_top Open the linked document in the full body of the window
framename Open the linked document in a named frame


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.


Thu Jul 21 01:03:03 2011
tag: cfd
Wed Jul 20 22:35:40 2011
tag: jquery
Sun Jul 17 21:20:53 2011
devinvenable: Grounded by Init Dot D via #soundcloud http://t.co/YxMGUnH
Wed Jul 13 07:33:15 2011
Huge gvim annoyance
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?

Same thing happens whether using vim-gnome or vim-gtk package.

Other programs do not share this quirk. For example, the text editor program behaves as expected when opening the files.
Thu Jul 7 17:49:50 2011
tag: music
Sat Jun 11 16:58:59 2011
tag: uml
Mon Jun 6 18:42:34 2011
tag: django
Mon Jun 6 14:53:15 2011
tag: ami
Sun Jun 5 18:19:43 2011
tag: None
Sat Jun 4 15:51:25 2011
devinvenable: How well does your browser handle HTML 5? http://html5test.com/
Thu Jun 2 20:06:03 2011
devinvenable: Rejiggering my WIKI. Need to bring the employers to me: http://wiki.devinvenable.com
Fri May 27 14:20:30 2011
devinvenable: SOAP is Not Dead - It's Undead, a Zombie in the Enterprise by @alexwilliams http://t.co/WBJ4TuT via @RWW
Thu May 26 20:06:03 2011
devinvenable: @adriap @valsavus Don't be mad at her. She can't help herself.
Wed May 25 08:32:37 2011
Can't ignore IE
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.

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!

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.

<!--[if IE]>
   You are using IE (IE5+ and above), so include include script that is specific for IE here.
<![endif]-->

<![if !IE]>
   You are NOT using IE, so feel free to use HTML 5 features.
<![endif]>


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.

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.

http://www.w3schools.com/browsers/browsers_stats.asp
Sun May 22 13:34:13 2011
Job search fun!
I've decided to make a transition. New opportunity, here I come!

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?"


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.

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.

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.

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.

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.

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. :)
Sun May 22 13:33:49 2011
OpenGL Intellivision Man
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:

http://www.youtube.com/watch?v=E1rXt0l2pxY

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.

The code I used to render the animation is a hack of an example found here:

http://code.google.com/p/pyglet-hene/source/browse/trunk/

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.

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:

ls -ltr
total 32
-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 9.bmp
-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 8.bmp
-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 6.bmp
-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 5.bmp
-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 4.bmp
-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 3.bmp
-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 2.bmp
-rw-r--r-- 1 dvenable dvenable 1654 2010-07-20 14:06 1.bmp


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.

And here's the complete source:

from pyglet.gl import *
import pyglet
from pyglet.window import *
from pyglet import image
import os
from PIL import Image
import glob
from math import sin, cos

window = pyglet.window.Window(width=640, height=480, resizable=True)

y=0.0
x=-10.0     
z=10.0    
xspeed = 0.5
yspeed = 0.0
lx=ly=0
lz=-2
angle=ratio=0.0

boxcol = [ [1.0, 0.0, 0.0], # bright: red
           [1.0, 0.5, 0.0],        # orange
           [1.0, 1.0, 0.0],        # yellow
           [0.0, 1.0, 0.0],        # green
           [0.0, 1.0, 1.0],        # blue
                        ]

# Dark: red, orange, yellow, green ,blue
topcol =[ [0.6, 0.0, 0.0],
          [0.6, 0.25, 0.0],
          [0.6, 0.6, 0.0],
          [0.0, 0.6 ,0.0],
          [0.0, 0.6, 0.6]]
                        


box = None # display list storage
top = None #display list storage

yloop = None # loop for y axis
xloop = None # loop for x axies

bmpdata = None 
nextimg = 0
files = None

def load_image_data():
    global bmpdata, bmpdatalen, files 

    files = glob.glob('data/*.bmp')
    files.sort()
    bmpdata = map(lambda x: Image.open(x).getdata(), files.__iter__())
    bmpdatalen = len(bmpdata)

 
def build_lists():
  global box, top
  box = glGenLists(2)

  glNewList(box, GL_COMPILE)    # new compiled box display list

  # draw the box without the top (it will be store in display list
  # and will not appear on the screen)
  glBegin(GL_QUADS)
  
  # front face
  glTexCoord2f(0.0, 0.0);       glVertex3f(-1.0, -1.0, 1.0)
  glTexCoord2f(1.0, 0.0);       glVertex3f(1.0, -1.0, 1.0)
  glTexCoord2f(1.0, 1.0);       glVertex3f(1.0, 1.0, 1.0)
  glTexCoord2f(0.0, 1.0);       glVertex3f(-1.0, 1.0, 1.0)
  # back face
  glTexCoord2f(1.0, 0.0);       glVertex3f(-1.0, -1.0, -1.0)
  glTexCoord2f(1.0, 1.0);       glVertex3f(-1.0, 1.0, -1.0)
  glTexCoord2f(0.0, 1.0);       glVertex3f(1.0, 1.0, -1.0)
  glTexCoord2f(0.0, 0.0);       glVertex3f(1.0, -1.0, -1.0)
  # right face
  glTexCoord2f(1.0, 0.0);       glVertex3f(1.0, -1.0, -1.0)
  glTexCoord2f(1.0, 1.0);       glVertex3f(1.0, 1.0, -1.0)
  glTexCoord2f(0.0, 1.0);       glVertex3f(1.0, 1.0, 1.0)
  glTexCoord2f(0.0, 0.0);       glVertex3f(1.0, -1.0, 1.0)
  # left face
  glTexCoord2f(0.0, 0.0);       glVertex3f(-1.0, -1.0, -1.0)
  glTexCoord2f(1.0, 0.0);       glVertex3f(-1.0, -1.0, 1.0)
  glTexCoord2f(1.0, 1.0);       glVertex3f(-1.0, 1.0, 1.0)
  glTexCoord2f(0.0, 1.0);       glVertex3f(-1.0, 1.0, -1.0)
  glEnd()

  glEndList()   # Done building the list

  top=box+1

  glNewList(top, GL_COMPILE)    # new compiled top display list
  # Top face
  glBegin(GL_QUADS)
  glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0)
  glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 1.0)
  glTexCoord2f(1.0, 0.0); glVertex3f(1.0, 1.0, 1.0)
  glTexCoord2f(1.0, 1.0); glVertex3f(1.0, 1.0, -1.0)
  
  glTexCoord2f(1.0, 1.0);       glVertex3f(-1.0, -1.0, -1.0)
  glTexCoord2f(0.0, 1.0);       glVertex3f(1.0, -1.0, -1.0)
  glTexCoord2f(0.0, 0.0);       glVertex3f(1.0, -1.0, 1.0)
  glTexCoord2f(1.0, 0.0);       glVertex3f(-1.0, -1.0, 1.0)
  glEnd()
  glEndList()


     
def load_gl_textures():
        # load bitmaps and convert to textures
        global texture, texture_file, texture_surf
        #texture_file = os.path.join('data', 'cube.bmp')
        texture_file = files[nextimg]
        texture_surf = image.load(texture_file)
        texture = texture_surf.get_texture()
        glBindTexture(GL_TEXTURE_2D, texture.id)

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)


        
def init():
    """
    Pyglet oftentimes calls this setup()    
    """
    glEnable(GL_TEXTURE_2D)

    load_image_data()
    load_gl_textures()
    build_lists()

    glShadeModel(GL_SMOOTH) # Enables smooth shading
    glClearColor(0.0, 0.0, 0.0, 0.0) #Black background
    
    glClearDepth(1.0)               # Depth buffer setup
    glEnable(GL_DEPTH_TEST)         # Enables depth testing
    glDepthFunc(GL_LEQUAL)          # The type of depth test to do

    glEnable(GL_LIGHT0) # quick and dirty lighting 
    
    #glEnable(GL_LIGHTING)  # enable lighting
    glEnable(GL_COLOR_MATERIAL)     # enable coloring

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)       # Really nice perspective calculations
       
    
     
@window.event
def on_draw():
    global nextimg, bmpdata, x, y, z, lx, ly, lz

    # Here we do all the drawing
    glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT)

    # Select the texture
    load_gl_textures()
    #glBindTexture(GL_TEXTURE_2D, texture.id)

    xloop = 1
    yloop = 1
    
    mandata = bmpdata[nextimg]
    for idx in range (0, len(mandata)):
        if (idx+1) % 24 == 0:
            yloop += 1
            xloop = 1
        else:
            xloop += 1
        if mandata[idx] < 100:

            glLoadIdentity()        # reset our view
            gluLookAt(x,y,z, x+lx , y+ly, z+lz, 0.0, 1.0, 0.0)

            glTranslatef( xloop*1.8 - 30 ,
                                      28 - yloop*2.4 ,
                                      -60.0)
            glColor3f(*boxcol[xloop % 4]) # select a box color
            glCallList(box) # draw the box

            glColor3f(*topcol[1])
            glCallList(top)  # draw the top


    return pyglet.event.EVENT_HANDLED
      
def moveMeFlat(direction):
    global x, z, y, lx, lz, ly 
    x = x - direction*(lx)*0.75;
    y = y + direction*(ly)*0.5;
    z = z + direction*(lz)*0.5;
 
def orientMe(ang):
    global lx, lz
    lx = sin(ang)
    lz = -cos(ang)
  

def update(dt):
    global z, angle
    angle +=0.005
    orientMe(angle)
    moveMeFlat(0.5)

def update2(dt):
    global nextimg
    if nextimg < bmpdatalen-1:
        nextimg += 1
    else:
        nextimg = 0 


pyglet.clock.schedule_interval(update2, .1)
pyglet.clock.schedule(update)
        
@window.event
def on_resize(width, height):
        if height==0:
            height = 1
        glViewport(0, 0, width, height)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

        # Calculate the aspect ratio of the window
        gluPerspective(45.0, 1.0*width/height, 0.1, 100.0)

        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        return pyglet.event.EVENT_HANDLED
        
init()  

pyglet.app.run()
Fri May 20 14:29:13 2011
devinvenable: Launching a job search today. Task #1: Replace silly pictures of self on social networking sites with serious, important looking photo.
Fri May 13 19:15:48 2011
devinvenable: @KristianRoebuck Django!
Tue May 3 16:21:30 2011
devinvenable: Ubuntu 11.04 upgrade...not smooth
Tue Apr 26 13:36:47 2011
Adding information to Django's default error page
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.

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.

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.

try:

    """
    This is where you build your view.  Do whatever you need to do.  In my case
    I was inserting a row into the database here.
    """
except Exception as inst:
    
    """
    inst.args is a tuple of arguments that were passed when the exception
    was raised.  Django will turn this variable into the main error message
    you see atop the default error page.  It's a tuple, so you can't append
    to it, but you can replace it with another tuple and add any information
    that would serve you well.
    """

    inst.args = ("%s sql:%s" % (inst.args[0], " ".join(connections[db].queries.pop()['sql'].split())),)

    """
    Sure that's ugly, but it served my debugging purpose.  Use pop to get the most 
    recent query from the queries list.  I wanted to get rid of the while space and
    newline characters, which is the reason for the split and join.  Now you just 
    raise the exception.
    """
    raise


If you are going to do this kind of thing frequently you should probably explore the process-exception middleware API.

http://docs.djangoproject.com/en/dev/topics/http/middleware/?from=olddocs#process-exception
Mon Apr 25 11:38:15 2011
Best Django debugging technique ever
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.

import pdb
pdb.set_trace


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!

Sweet! I can't believe I didn't know about this technique before.
Thu Apr 7 19:21:39 2011
devinvenable: I'm playing again at Eclipse tonight at 9:30. If you are living on Tulsa Time, come on by and hang with me and the other musicians.
Tue Apr 5 19:13:13 2011
devinvenable: If you live in Tulsa, come by Eclipse Thursday night, April 7th at 9:30 to see performances by Init Dot D and other local musicians.
Fri Apr 1 21:05:58 2011
devinvenable: Cinelerra is ugly and somewhat difficult to use and learn, but it's one powerful video editor.
Tue Mar 29 13:23:06 2011
devinvenable: I'm reading Data Analysis with Open Source Tools by Philipp K. Janert. Love O'Reilly books.
Mon Mar 28 12:13:02 2011
Dansguardian and Youtube on Ubuntu 10.10
If you want content filtering for your kids on Ubuntu 10.10, Dansguardian does the trick, but be prepared to do some tweaking.

Installation is not difficult. Follow this recipe:

https://help.ubuntu.com/community/Servers/DansGuardian

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.

I added the following file extensions to exceptionextensionlist:

.js
.flv
.mp3
.ico


From bannedregexpurllist, I removed the keyword "naked", which seemed a bit over the top to me.

For video playback, add this line to exceptionurllist:

youtube.com/videoplayback


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.

ytimg.com


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.
Fri Mar 18 15:25:43 2011
198252_1615661556849_1395634786_31310498_7106841_n
Thu Mar 17 12:50:05 2011
Color highlight columns in Vim
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.

Vim 7.3 is not yet in the Ubuntu repositories officially, but a PPM is available here:

http://askubuntu.com/questions/7283/where-can-i-find-vim-7-3

Once installed, use vim help to get details about colorcolumn.

:help colorcolumn


This will show you:

'colorcolumn' 'cc'      string  (default "")
                        local to window
                        {not in Vi}
                        {not available when compiled without the |+syntax|
                        feature}
        'colorcolumn' is a comma separated list of screen columns that are
        highlighted with ColorColumn |hl-ColorColumn|.  Useful to align
        text.  Will make screen redrawing slower.
        The screen column can be an absolute number, or a number preceded with
        '+' or '-', which is added to or subtracted from 'textwidth'. 

                :set cc=+1  " highlight column after 'textwidth'
                :set cc=+1,+2,+3  " highlight three columns after 'textwidth'
                :hi ColorColumn ctermbg=lightgrey guibg=lightgrey

        When 'textwidth' is zero then the items with '-' and '+' are not used.
        A maximum of 256 columns are highlighted.



In practice you only need to :set cc=n, as there are default colors.
Thu Mar 3 10:59:56 2011
History in Python shell
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.

Here's what you do. Store the following file in ~/.pystartup

Don't forget to export PYTHONSTARTUP as noted in the comments.

# Add auto-completion and a stored history file of commands to your Python
# interactive interpreter. Requires Python 2.0+, readline. Autocomplete is
# bound to the Esc key by default (you can change it - see readline docs).
#
# Store the file in ~/.pystartup, and set an environment variable to point
# to it:  "export PYTHONSTARTUP=/home/user/.pystartup" in bash.
#
# Note that PYTHONSTARTUP does *not* expand "~", so you have to put in the
# full path to your home directory.

import atexit
import os
import readline
import rlcompleter

readline.parse_and_bind('tab: complete')
historyPath = os.path.expanduser("~/.pyhistory")

def save_history(historyPath=historyPath):
    import readline
    readline.write_history_file(historyPath)

if os.path.exists(historyPath):
    readline.read_history_file(historyPath)

atexit.register(save_history)
del os, atexit, readline, rlcompleter, save_history, historyPath


Please note that this will only work on *nix systems. As readline is only available in Unix platform.
Wed Nov 24 07:31:05 2010
Thank God for Tripper McCarthy
A long time ago, in our galaxy, Tripper McCarthy posted this:

Tripper McCarthy  Tue Jun 24 2003 19:19:31 GMT-0500 (CDT) 

 There have been several posts asking how to change the body of a message
(not the header) from within a handler. Here is a way to pull it off. It's a
little strange, but it works. 

    public void invoke(MessageContext msgContext) throws AxisFault {
        try {
            javax.xml.soap.SOAPMessage soapMessage =
msgContext.getRequestMessage();
            String oldRequest =
soapMessage.getSOAPPart().getEnvelope().toString();
            
            int index = oldRequest.indexOf("
            index = oldRequest.indexOf(">",index);
            String newRequest = oldRequest.substring(0,index+1) +
                "5" +
                oldRequest.substring(index+1,oldRequest.length());
            
            ByteArrayInputStream istream = new
ByteArrayInputStream(newRequest.getBytes());            
            Message msg = new Message(istream, false);
            msgContext.setRequestMessage(msg);

        }
        catch(Exception e) {
            e.printStackTrace();
            throw new AxisFault(e.getMessage());
        }
    }


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.
Mon Oct 25 09:13:44 2010
RedHat Enterprise 5 and Python
Update:

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.



Python 2.4 is the python that ships with RedHat Enterprise Linux 5. This will never do.

I didn't remove 2.4 because some suggested against it, saying that RedHat needs to keep this version around.

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.

update-alternatives --config python


Run Python again and your system wide default should now be the latest version you installed.

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.
Fri Oct 22 10:59:42 2010
Shrink PDF file on linux (command line)
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET -sPAPERSIZE=a4 -dBATCH -sOutputFile=output.pdf input.pdf
Thu Oct 14 17:28:25 2010
Convert 32 to 16 bit WAV (Linux) recipe
Check file info:

devin@studio:~/Music/samples$ sndinfo funky.wav 
virtual_keyboard real time MIDI plugin for Csound
PortMIDI real time MIDI plugin for Csound
PortAudio real-time audio module for Csound
util sndinfo:
funky.wav:
 srate 44100, stereo, 32 bit WAV, 9.835 seconds
 (433737 sample frames)


Convert to 16 bit:

sox funky.wav -b 16 funky16.wav
Thu Sep 9 09:44:34 2010
cx_Oracle and out cursor
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.

connection = cx_Oracle.connect(connstr)
cursor = connection.cursor()
out = cursor.var(cx_Oracle.CURSOR)

items = cursor.callproc('EXAMPLE_PKG.get_some_data',
                ['02-SEP-2010',
                '03-SEP-2010',
                332123.0,
                896798.0,
                68567.0,
                'xyz',
                out
                ]

print items[6].fetchall()


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.

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.
Tue Jul 20 07:31:04 2010
Cross-compile ActiveMQ-cpp on Centos 5
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.

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:

Install dependencies:

yum install expat-devel zlib-devel uuid-c++-devel openssl-devel


Download sources from here or other mirrors:

wget http://www.carfab.com/apachesoftware/activemq/activemq-cpp/source/activemq-cpp-library-3.2.1-src.tar.gz
wget http://mirror.candidhosting.com/pub/apache/apr/apr-1.4.2.tar.gz


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.

[root@myserver] cd apr-1.4.2
[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 
[root@myserver] ./make
[root@myserver] ./make install


Next build and install ActiveMQ-cpp:

[root@myserver] cd ../activemq-cpp-library-3.2.1
[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
[root@myserver] ./make
[root@myserver] ./make install
Tue Jul 13 07:18:18 2010
qemu-img
qemu-img is a handy tool for converting one virtual machine image format into another.

qemu-img convert windowsxp.img -O vdi windowsxp.vdi


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.

 dd if=/dev/zero of=vm8.img bs=2048k count=12000
 kvm -m 512 -cdrom winxp.iso -boot d v8.img


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.

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.

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.

And that's where qemu-img came in. virtualbox only reads vmi formatted images, thus I converted my raw image to vmi.

Updated: FAIL

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:

"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."

Okay...but I will silently resent you.

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...
Wed Jul 7 15:28:29 2010
Going really 8-bit
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.

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 video project.

Some of my video conversion notes were covered in another post and some are on my wiki.

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.

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.

ffmpeg -i intel.avi -r 4 -s 24x24 intel8bit.avi

Next I extracted individual bitmap images:

ffmpeg -i intel8bit.avi -f image2 foo_%5d.bmp

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.

from PIL import Image
import sys, os

def bw(pt):
    if pt>126:
        return 255
    else:
        return 0

for infile in sys.argv[1:]:
    f, e = os.path.splitext(infile)
    outfile = f + "_mod" + e

    im = Image.open(infile)

    im = im.convert('L')
    out = im.point(bw)

    out.save(outfile)
    print outfile


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.)

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.

At this point I have true black and white bitmaps.

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.

from PIL import Image
import sys, os


for infile in sys.argv[1:]:

    im = Image.open(infile)
    data = im.getdata()
    for idx in range (0, len(data)):
        i = data[idx]
        if i == 255:
            print 'X',
        else:
            print ' ',

        if (idx+1) % 24 == 0:
            print ''


The output looks like this:

devin@studio:~/src/py$ python showdata.py /home/devin/Video/bitmaps/foo_00041_mod.bmp 

X X X X X X X X X X X X X X X X X X X X X X X X 
X X X X X X X X X X X X X X X X X X X X X X X X 
X X X X X X X X X X X X X X X X X X X X X X X X 
X X X X X X X X X X X X       X X X X X X X X X 
X X X X X X X X X X X X     X X X X X X X X X X 
X X X X X X X X                   X X X X X X X 
X X X X X                   X X X X X X X X X X 
X X X X X                   X X X X X X X X X X 
X X X X X                   X X X X X X X X X X 
X X X X X                     X X X X X X X X X 
X X X X X X                       X X X X X X X 
X X X X X X X X         X X X X X X X X X X X X 
X X X X X X X X             X X X X X X X X X X 
X X X X X                         X X X X X X X 
X X X X X     X X X X X X X X     X X X X X X X 
X X X X X     X X X X X X X X     X X X X X X X 
X X X X X     X X X             X X X X X X X X 
X X X X X     X X X     X X X X X X X X X X X X 
X X X X X     X X X X X X X X X X X X X X X X X 
X X X X X     X X X X X X X X X X X X X X X X X 
X X X X X X X X X X X X X X X X X X X X X X X X 
X X X X X X X X X X X X X X X X X X X X X X X X 
X X X X X X X X X X X X X X X X X X X X X X X X 
X X X X X X X X X X X X X X X X X X X X X X X X
Tue Mar 16 15:51:21 2010
JSON API
Tue Mar 16 15:51:20 2010
XML API
Tue Mar 16 15:51:20 2010
Mashup Editor
Tue Mar 16 15:51:19 2010
Object with links to Related Records
Tue Mar 16 15:51:19 2010
Search Result Page
Fri Mar 12 21:28:26 2010
Sitting Under Canvas (8-bit)
Thu Feb 11 19:24:07 2010
I love my retro layout.
Mon Dec 28 15:24:03 2009
ZynAddSubFX Packaged
Mon Dec 28 15:24:02 2009
ZynAddSubFX Compiled
Fri Nov 20 19:54:23 2009
lolas
Thu Nov 19 19:13:45 2009
Crypto Nerd's Imagination