Outlook Macro : Move to Specified Folder & Mark As Read
Tuesday, April 22 2008 @ 12:54 PM CDT
As a victim of Microsoft Outlook, I hear alot about using it in the GTD philosophy. One of my favorite websites, LifeHacker, extolls it's virtues (GTD, not Outlook) on a daily basis. Yesterday they posted an article about how to modify your toolbars to give you shortcut keys for "Copy to folder" and "Move to folder" actions. I don't know why I never thought of that before.
I quickly set that up, and then realized I could add an additional shortcut for "Mark as Read" (our IT staff has disabled the ability to Mark as Read when Previews). With those in place, I decided I might actually try another GTD point: an empty inbox. The key to an empty inbox is to have a place to dump mail you've read and responded to, but don't really need anymore except for reference. They call it an "Archived" or "Processed" folder. While I could do this with the "Move to" shortcut, I had to select the folder everytime. With a bit of googling, I was able to setup an Outlook VB Macro (Under the Tools Menu) to Mark the message as read and move it to my personal PST file, in a folder called "Ancient Archive".
For everyone else's benefit, the VB code is as follows:
| Sub MoveToArchive() On Error Resume Next Dim objFolder As Outlook.MAPIFolder Dim objNS As Outlook.NameSpace, objItem As Outlook.MailItem Set objNS = Application.GetNamespace("MAPI") Set objFolder = objNS.Folders("Personal Folders").Folders("Ancient Archive") 'Assume this is a mail folder If objFolder Is Nothing Then MsgBox "This folder doesn't exist!", vbOKOnly + vbExclamation, "INVALID FOLDER" End If If Application.ActiveExplorer.Selection.Count = 0 Then 'Require that this procedure be called only when a message is selected Exit Sub End If For Each objItem In Application.ActiveExplorer.Selection If objFolder.DefaultItemType = olMailItem Then If objItem.Class = olMail Then objItem.UnRead = False objItem.Move objFolder End If End If Next Set objItem = Nothing Set objFolder = Nothing Set objNS = Nothing End Sub |
Technorati Tags: outlook, gtd, lifehacker, macro
Freezerburn - Screenshots in Action
Wednesday, April 16 2008 @ 03:41 PM CDT
So, I've talked a good bit about the technical guts of Freezerburn, so I figure it's about time to show what it looks like. Here is a screenshot of the Job Details page (in IE6 unfortunately, so the transparent PNG's are a big nasty).
Up top you see some basic statistics about the server. Right below that you see the progress of the entire job, and then the progress of all the frames. Each little box indicates a frame.
- Green box - Frame is completed
- Striped box - It's a Mental Ray frame, and the three stripes indicate percentage complete of either Photon Emission (top bar), Final Gather (middle bar), or Rendering (bottom bar)
- Spotted Box - some other unrecognized render stage
- Red box (not shown) - Errored frame
- Grey box - unassigned frame
Comments?
Technorati Tags: freezerburn, max, queue, render
Laura is now an RHIT, CCS
Monday, April 14 2008 @ 01:57 PM CDT
Just wanted to make a nice public announcement that now Laura is an RHIT, CCS! She took her CCS Certification exam this weekend and passed with flying colors! Congratulations Laura!
Technorati Tags: certification, ahima, ccs
Aquaria
Monday, March 31 2008 @ 09:51 AM CDT![]()
This weekend I was digging through old bookmarks and dug up an old reference to a game called Aquaria. I first heard of Aquaria when it won the IGF2007 Grand Prize, but it wasn't available for download at the time. Now, they have a good 60M Demo of the game (good for 2 hours or so of playtime), and for $30 you can get the full 250M version. I've been playing it all weekend, and after 6 hours of playtime (according to my savegame) I'm still finding new stuff and continually being astounded by the game.
The graphics are simply beautiful. The entire game is a side-scroller basically, but with lots of little bells and whistles. Seaweed and flowers flow as you swim by, matching your movements. Schools of fish following true flocking behavior swimming around. The environment changed from lush green landscapes, to barren castle hallways, to eerie organic fleshly tunnels, and all done seamlessly. The music is even more impressive. An eerie lonely tune that adds to the mystery of "Who am I?", with fast-paced music added for boss fights and action scenes. The cut-scenes are great, and the british accent voiceovers are a perfect match.
At it's heart, Aquaria is a puzzle game with a little bit of combat. Primarily you're searching for new "forms" (spells) to give you new abilities, but usually each form comes with solving a puzzle. Boss fights are there, but are usually puzzle-based. Eg. The boss has only a single special weakness that you have to discover and exploit.
The game is a blast, and I'm catching myself humming the theme music constantly. I look forward to seeing how the story plays out, and seeing what other fantastic environment there are for me to explore.
Technorati Tags: game, indie, aquaria
Webservers with Python - SSL & CAC Authentication
Tuesday, March 25 2008 @ 01:11 PM CDT
Working in the DOD, there are a few things you just come to accept. Webservers require security (SSL), and SSL requires Common Access Card Authentication. I had hoped that when I implemented the HTTP Monitor for Freezerburn, I could ignore all the security aspects and simply say that "It's behind all the government firewalls" and "It requires an account on the fileserver". I wasn't so lucky.
After alot of research from articles like:
import socket, osThis creates a new object called the "SecureHTTPServer" that acts just like the regular HTTPServer, except it allows you to specify the location of the DOD Root Certificates, the Server Private Key, and the Server SSL Certificate. The only real difference from the ASPN one is that it turns on Client Certificate Verification, which is the core of the CAC Authentication scheme. With that little snippet of code, SSL & CAC were enabled in one fell swoop!
from SocketServer import BaseServer
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from SocketServer import ThreadingMixIn
from OpenSSL import SSL
import sys
class SecureHTTPServer(HTTPServer):
def __init__(self, server_address, HandlerClass,
dodcerts, serverkey, servercert):
BaseServer.__init__(self, server_address, HandlerClass)
# Based on online Documentation, the v23 actually enables TLS1 as well.
ctx = SSL.Context(SSL.SSLv23_METHOD)
#ctx = SSL.Context(SSL.TLSv1_METHOD)
print "Loading Private Key from %s" % serverkey
ctx.use_privatekey_file (serverkey)
print "Loading Certificate from %s" % servercert
ctx.use_certificate_file(servercert)
print "Loading DOD Certifications from %s" % dodcerts
ctx.set_verify_depth(2)
ctx.load_client_ca(dodcerts)
ctx.load_verify_locations(dodcerts)
print "Creating SSL socket"
callback = lambda conn,cert,errno,depth,retcode: retcode
ctx.set_verify( SSL.VERIFY_FAIL_IF_NO_PEER_CERT | SSL.VERIFY_PEER, callback)
ctx.set_session_id('Freezerburn')
self.socket = SSL.Connection(ctx, socket.socket(self.address_family,
self.socket_type))
self.server_bind()
self.server_activate()
class SecureHTTPRequestHandler(SimpleHTTPRequestHandler):
def setup(self):
self.connection = self.request
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
Technorati Tags: ssl, python, cac
Family Pics
Wednesday, March 19 2008 @ 03:55 PM CDT
Technorati Tags: myspace, pics
Webservers with Python - Caching
Wednesday, March 19 2008 @ 03:32 PM CDT
One thing I decided very early on with FreezerBurn was the need for a Web-Based monitoring tool. I didn't want to have to deploy a Python tool with a full user-interface to every desktop and then deal with all the Security implications of that. With a web interface, I could simply let everyone use FireFox or IE or Safari and load it however they wanted. At least, that was the initial idea.
Very quickly I came across Python's HTTPServer class which handles a good 90% of what I needed. After some experiments, though, I found that it tended to die under heavy loads (eg, loading my page with external JS, CSS, and Images). I needed it to be fairly reliable, and thusly discovered alot more then I ever intended to about HTTP Caching.
HTTP implements caching 2 ways: ETags & "Last-Modified" dates. Etags are simply checksums where the Browser says "The version I have has this checksum", and the server checks it and tells you "That's right" or "That's old, here's a new one". In my case, I chose to instead implement the "Last-modified" version where I could simply check the last modified date on the files. The resulting code looks like this:
class MonitorServer(HTTPRequestHandler):So, this piece of code creates a "MonitorServer" object and defines the "GET" function. In there it parses the requested URL, and if it's in one of a few selected forms then send the dynamically generated content. Otherwise, send the requested file directly to the User. As a security precaution, I don't allow the user to specify a path (the path is stripped and the file must exist within 1 specific directory). If the browser provides a "If-None-Match" header, then I return a 304 code which indicates the Cache is up-to-date. If they provide a "If-Modified-Since", then I parse the date and compare it against the file, and returna 304 if appropriate. One interesting thing I learned from this is that the Browser doesn't actually return the date of the file, but rather returns the "Last-Modified" you send it, in identical formatting.
def do_GET(self):
global jobQueue
global servers
global mQueue
global initTime
# process self.path
(scm, netloc, path, params, query, fragment) = urlparse.urlparse(self.path, 'http')
if scm != 'http' or fragment:
self.send_error(400, "bad url %s" % self.path)
return
print 'HTTP: Serving %s' % path
# Write to self.wfilt
if path == "/":
# Raw Index Page
self.wfile.write(""" blah blah blabh """)
elif path == "/job":
blah blah blah
else:
# Serve files from the system
path = path.split('/')[-1]
if os.path.exists(constants.MonitorPath + '\\' + path):
(ctype, enc) = mimetypes.guess_type(path)
info = os.stat(constants.MonitorPath + '\\' + path)
lastmod = datetime.datetime.fromtimestamp(info[ST_MTIME])
if self.headers.get('If-None-Match',''):
self.send_response(304)
return
if self.headers.get('If-Modified-Since',''):
dt = self.headers.get('If-Modified-Since').split(';')[0]
try:
modsince = datetime.datetime.strptime(dt, "%a, %d %b %Y %H:%M:%S %Z")
if modsince >= lastmod:
print "HTTP: No new version of %s" % path
self.send_response(304)
return
except:
pass
self.send_response(200)
self.send_header('Cache-Control', 'max-age=864000')
self.send_header('Expires', "Fri, 30 Jan 2010 12:00:00 GMT")
self.send_header('Content-Length', info[ST_SIZE])
self.send_header('Last-Modified', lastmod.strftime("%a, %d %b %Y %H:%M:%S GMT"))
self.send_header('Content-Type', ctype)
self.end_headers()
self.copyfile(open(constants.MonitorPath + '\\' + path, 'rb'), self.wfile)
else:
print "MONITOR:Can't find %s" % (constants.MonitorPath + '\\' + path)
self.send_error(404, "Unknown url %s" % self.path)
So far, this works great! It significantly improved the response of the server and has greatly reduced load-times (Even though it's on a local-network).
Technorati Tags: python, webserver, caching
Freezerburn : a Replacement for BackBurner
Tuesday, March 11 2008 @ 10:47 AM CDT![]()
Anyone who's used Autodesk's 3D Studio Max for a while knows about BackBurner. BackBurner is the Queue-controlling software they ship with Max to allow you to render jobs across multiple scenes in a naive way. Rather than pooling resources to work on a single frame, it hands out individual frames of the sequence to each node in the backburner queue. (You can pool resources using the "Strip" rendering, but it's pretty much the same thing). However, the way we use BackBurner at work has proven to us that it's just a piece of crap. Thus, I wrote my own queue manager that I've dubbed "Freezerburn". Let me elaborate..
In our environment, we typically get a dataset of 1000 or so timesteps. We extract 1000 isosurfaces (one from each timestep), and then need to render these 1000 files into 1000 frames of an animation (For those interested, we typically save the isosurfaces as Stanford PLY files and use the PLY import plugin I wrote, along with a MaxScript, to convert them all into MAX files). So we create a simple setup scene with the context, lights, and camera. We then use another custom MaxScript I developed to embed a callback into the Max File's "onLoad" event that will look at the current frame number, merge in the appropriate Max file, and apply whatever material properties we need. That way we have a single MAX file that can render all 1000 frames of the animation. Unfortunately, since it's in the onLoad, it means we need to load this Scene file from disk for each image.
With Backburner, you have no control over this. With a large scene, it typically starts off assigning individual frames to nodes, which is exactly what we want. After those complete, however, it starts assigning larger & larger batches of frames to each node (to reduce overhead spent loading the file & transmitting information). This means that the onLoad callback is only triggered once but renders multiple frames, which isn't what we want.
The technical amongst you may be wondering "Why not just use preRenderFrame"? Well, there's a few reasons while the various preRender callbacks won't work like that:
- preRender - Only called once at the beginning of the entire render, basically no better than onLoad
- preRenderFrame - Called between every frame, but after geometry is cached.. Attempting to change geometry (eg. Merge in a new Max File) results in a SegFault
- beginRendering* - Same as preRenderFrame
- preRenderEval - I had high hopes for this when I first saw it, but it seems to operate identically to preRender (only once at the beginning of the entire render)
So my solution was to use my new Python skills to write our own queue manager. It's written entirely in Python, and offers the following features:
- Queue & priority control
- For Mental Ray scenes it gives you % complete on each of the 3 major stages of render (Preprocessing, Final Gather, Rendering)
- Vastly improved "at-a-glance" status information
- Controllable via a Web Interface (with SSL certificates and CAC authentication which is required where I work)
- And much much more...
Technorati Tags: autodesk, backburner, python
MAKO finally IPO's
Monday, March 03 2008 @ 08:45 AM CST
A friend of mine tipped me off to the fact that MAKO finally made their IPO last month. I had completely missed it (which is probably a good thing). So I hit up Google's Financial pages to see the trading charts..

While this may look good at a glance, a quick look shows nothing of note. They opened just under $10, spiked to $12, and settled down around 10.50 for today. What I find more interesting is the harsh commentary on it... Like the Wall Street Journal:
MAKO closed at $9.18 a share on the Nasdaq, down 8% from its IPO price of $10. It sold 5.1 million shares at the low end of a reduced $10 to $11 price range; it originally was expected to price between $14 to $16 through underwriters J.P. Morgan Chase & Co. and Morgan Stanley.So, looks like noone will be selling their shares and buying a Yacht anytime soon. Guess we'll just have to wait and see how it plays out.
...
Meanwhile, Fort Lauderdale, Fla.-based MAKO specializes in making robotic instruments and implants for knee surgery. Its products, which were first cleared by the Food and Drug Administration, allow surgeons to avoid complete joint replacement for early-to-mid-stage osteoarthritic knee disease, and instead resurfaces damaged joints and places implants through a small incision.
MAKO has never been profitable and expects to continue losing money as it develops its business.
Technorati Tags: mako, stockmarket
Project Management with Trac & SVN
Wednesday, February 27 2008 @ 01:59 PM CST![]()
Back at Z-Kat, I remember we spent alot of time trying to get a web-based project management system up and running. We were already using CVS for source control, and we had a Twiki advocate on staff who got Twiki up and running, and we eventually setup BugZilla for ticket tracking. It all worked pretty well in it's individual pieces, when you wanted to start linking things together it got a big confusing. We eventually wrote some code to allow us to reference ticket numbers from CVS commits, and put some stuff in the Wiki to let us reference things. With CVSWeb operating, it was almost a project management system but always felt a bit kludgey.
Well, with Final Colony taking off and myself and a friend working on it, I thought we needed something similar. Not wanting to rebuilt the previous solution, I dug around the net and eventually found Trac. It does everything the previous solution I mentioned did and more. It's got an integrated Wiki & Ticketing system, and links with Subversion for source control. It all cross-links so that you can directly reference code & changesets in wiki edits & tickets, and vice versa. They provide SVN post-commit-hooks to even allow you to commit code with a message that says "This fixes #45 and #46" and have those two tickets closed, with the SVN commit message added to the ticket. It's a complete & powerful system that does everything I need. It's written entirely in Python, and can be a bit of a Bear to install, but it's worth it. And if you don't have access to Apache, they even provide a standalone python version you can run on your own machine to manage data.
The one hurdle I had to overcome was converting my existing CVS repository to SVN. For this, I found a great tool called cvs2svn that converts your repository with full revision history, branches, and tags. Since then I've fallen in love with SVN. Life is so much easier than with CVS. All your changesets are full transactions, so never again do I commit a bunch of files and have it die halfway through with a version mismatch. Never again do I have to find cryptic date & timestamps to checkout a complete working version, just get "Version 738". I remember Lou's masterful TCL scripts to attempt & cobble together data like the "Date" of a Tag. Such things are trivial with SVN.
So, for those of you out there doing development that have not had the opportunity to use subversion & Trac, i highly recommend it. It's a great solution to so many of the problems I spend my days complaining about.
Technorati Tags: trac, subversion, software, project


