Randall's Blog

a place for my thoughts

Launched Checklist Web Application

written by randall, on Nov 3, 2011 1:55:00 PM.

I like to take a list with me when I shop to make sure I don't forget things. I use an app on my phone to make my checklist and I've often wished my wife could update the list for me remotely. So I created an application to do just that. It's a web application with very low bandwidth requirements and big buttons to make it easy to use on a phone. There's a demo on the website so you can play around with it.

Our Checklist

Check it out and I'd appreciate feedback.

Health Care Reform - Take 1

written by randall, on Nov 2, 2011 5:35:00 PM.

Summary

I propose a reform for the U.S.'s health care system that hinges on preventative care and physician ethics. It would result in drastically smaller health care costs overall, lower insurance costs, better general health among the population and a restoration of physicians' respect and admiration in society.

Though there may be alternative payment methods to insurance, I'll refer to the insurance payment system because it is familiar. Premiums would be based on a person's compliance with regular physical check-ups. A person's physician would attest that he has performed the required check-ups and complied with the physician's recommendations for maintaining or improving health. The person's compliance to the physician's recommendations would result in lower insurance premiums.

A person's non-compliance with a physician's recommendations would result in higher premiums and/or exemption for the insurance company from obligations to pay for treatments resulting from lack of compliance (e.g. smoking). Compliance determination is performed by a physician or board of physicians tasked with making ethical decisions with regards to these issues. The ethical execution of this duty is the basis for the entire system. Therefore, it is imperative that these physicians adhere to the highest level of ethical behavior.

This system encourages preventative health care, which is key to reducing overall costs. It leaves insurance to take care of the "unexpected" and unfortunate illnesses instead of the ones easily prevented, such as obesity and smoking. As with any system it doesn't create a utopia; there will still be those who refuse to take care of themselves and run up E.R. costs and the like, which somebody will have to pay, but I believe the benefits far outweigh the pitfalls.

dovecot imap server with indexing

written by randall, on Feb 15, 2010 1:31:00 AM.

I've run my own imaps server for a while (wu-imap), but it was getting slow mainly due to large files (using mbox mail format). I considered switching to maildir format and I considered a 3rd party host. While researching mail hosts, I got off track (as I often do) and ran across dovecot. The killer feature for me is indexing. My main email client (Thunderbird) is very responsive now. The first access to a mailbox is normal speed, but after it's indexed, access times are seemingly instant. You can read details about dovecot's indexing strategy here.

Complete I.T. Centralization is Bad

written by randall, on Dec 22, 2009 5:27:00 PM.

It seems that a common practice of businesses today is to isolate the I.T. staff from the business units. This works fine for operations that don't require knowledge of the business like supporting email and networking, but is terribly deficient beyond that limited scope. There are a limited number of cookie cutter operations that can be run with off the shelf software. At the point where the business becomes distinguished from others, its software must be customized or custom built to accommodate requirements specific to that business. It's at this point where centralized I.T. fails.

My view is primarily from my personal experience. I graduated from a mechanical engineering program and went into the engineering field. Enthusiasm for programming and ample opportunity to apply it led me into full time programming. My understanding of the business allowed me to identify areas with a high (efficiency gain) / (programming time) ratio and target those. Also, because I had a good working relationship with the other employees, I was able to get good feedback and make adjustments promptly.

Many of the rules and procedures of the business were complex and took time and experience to understand. One thing I've noticed about the centralized I.T. employees is that they typically like to stay in their I.T. bubble. For projects requiring specific business knowledge, they want someone else to figure out that stuff and just give them a specification.

I think it really boils down to something simple. For software to help run a business, it must know how the business runs. The better the business practices are understood and written into the software, the more helpful that software can be. So how can a person with little or no understanding of a business create useful software for it?

A good solution to the problem would be to take a programmer from the group and assign her to a business unit. She should become familiar with what each person does and how each job serves the business objectives. This knowledge would help her to identify areas where she can make improvements and enable her to give better advice and contribute more in general.

Using XPath Select with Genshi's Match Template

written by randall, on Oct 4, 2009 10:51:00 PM.

This entry details how I used Genshi's match templates for a two column layout with each column receiving template data. The key is XPath support and I found this page to be very helpful. Also, the genshi tutorial.

The thing to pay attention to is the syntax for "select". Both columns in the layout are selected using the XPath syntax //tag[@attribute='id_name']. So within the body that has been matched, the div with id="content" can be selected using this syntax:

    ${select("//div[@id='content']")}

The Layout Template (layout_template.html)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://genshi.edgewall.org/" py:strip="">
<py:match path="head" once="true">
<head py:attrs="select('@*')">
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title py:with="title = list(select('title/text()'))">
    My Site - <py:if test="title">${title}</py:if>
</title>
</head>
</py:match>
<py:match path="body" once="true">
<body py:attrs="select('@*')">
	<!-- header stuff goes here -->
	<div id="page">
		<div id="content" py:strip="">
            ${select("//div[@id='content']")}
		</div>
		<!-- end #content -->

		<div id="sidebar" py:strip="">
            ${select("//div[@id='sidebar']")}
		</div>
		<!-- end #sidebar -->
		<div style="clear: both;">&nbsp;</div>
	</div>
	<!-- end #page -->
	<!-- footer stuff goes here -->
</body>
</py:match>
</html>

The Index Template (index_template.html)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:py="http://genshi.edgewall.org/"
>
<xi:include href="layout_template.html" />
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Index Page</title>
</head>
<body>
    <div id="page">
        <div id="content">
            <p>your content</p>
	</div>
	<!-- end #content -->
        <div id="sidebar">
            <p>sidebar stuff</p>
	</div>
	<!-- end #sidebar -->
    </div>
    <!-- end #page -->
</body>
</html>

wxPython flags

written by randall, on Sep 16, 2009 12:11:00 AM.

I needed to use the wx.FindReplaceDialog from wxPython and got stumped when I wanted to see if a particular flag was set from a FIND/FIND_NEXT event. The flags to check are wx.FR_MATCHCASE, wx.FR_DOWN and wx.FR_WHOLEWORD. I've set flags many times for styles and such, but never before needed to check one.

Flags in wxPython (and wxWidgets of course) are set by applying a bitwise or to them. Example:

wx.FR_MATCHCASE | wx.FR_WHOLEWORD

This would include both wx.FR_MATCHCASE and wx.FR_WHOLEWORD, but exclude wx.FR_DOWN. The flags are retrieved using the evt.GetFlags method. So how do you know if a particular flag is set? Use bitwise and on evt.GetFlags() and the flag you are checking.

evt.GetFlags() & wx.FR_WHOLEWORD

This will return 0 if the wx.FR_WHOLEWORD flag is not set or a positive integer otherwise.

Create Reports using SVG Templates

written by randall, on Aug 6, 2009 4:37:00 PM.

A job I often encounter and have approached many ways is report creation. An oversimplified description is presenting data in a format that's useful to the recipient. When looks don't matter much, this can be as easy as creating an HTML template and merging the results of a database query, but when looks do matter the best solution isn't always apparent.

For the case when looks matter, I prefer PDF documents for the final output. The hard part is getting from raw data to PDF. Being a Python programmer I've used the reportlab library to this end with success, but often it's laborious. Also, because programming is required, non-programmers aren't able to create these reports. Many tools for end-user report creation require proprietary software and/or non-standard template formats and processes.

So what I'm looking for is:
  • template based
  • produce print ready PDF files
  • usable by non-programmers
  • use standard formats
The tools I found to meet these requirements are:
  • python (of course)
  • cairo
  • rsvg
  • Inkscape (for svg templates)

The templates are created and maintained using Inkscape in its native SVG format. In the SVG file, template fields are added as {FIELD1}, {FIELD2}, etc. A database query is run, returning fieldnames that match those in the template then python, rsvg and cairo handle template substitution and conversion to PDF.

Sample Code

def processSVGTemplate(template, data):

    filename = createNewUniqueFile()
    new_svg_file = open(filename, 'wb')

    # no need to make it difficult with xml parsing
    # just do find/replace
    svg_data = open(template).read()
    for (key, value) in data.items():
        svg_data = svg_data.replace('{%s}' % key, value)
    new_svg_file.write(svg_data)
    new_svg_file.close()

    return filename


def mergeData(template_name, data, output_path=None):
    """merge `data` with `template_path`

    returns None if `output_filename` is given or a string otherwise

    """
    template_path = os.path.join(TEMPLATE_PATH, template_name)
    # if not writing to a file, just send back a string.
    using_tempfile = False
    if output_path is None:
        using_tempfile = True
        output_path = createNewUniqueFile()
    try:
        svgt = rsvg.Handle(template_path)
        props = svgt.props
        pdf_dpi = 72.0
        width = pdf_dpi / svgt.props.dpi_x * svgt.props.width
        height = pdf_dpi / svgt.props.dpi_y * svgt.props.height
        # convert to 72 ppi
        surf = cairo.PDFSurface(output_path, width, height)
        cr = cairo.Context(surf)
        # scale the context for the change in dpi
        cr.scale(pdf_dpi / svgt.props.dpi_x, pdf_dpi / svgt.props.dpi_y)
        for rset in data:
            svg_filename = processSVGTemplate(template_path, rset)
            try:
                svg = rsvg.Handle(svg_filename)
                svg.render_cairo(cr)
                cr.show_page()
            finally:
                os.unlink(svg_filename)
        surf.finish()
        if using_tempfile:
            pdf_data = open(output_path).read()
            return pdf_data
    finally:
        if using_tempfile:
            os.unlink(output_path)

Caveats and Thoughts

  • rsvg required installing python-gnome-desktop on Debian (45Mb), which makes no sense to me.
  • I didn't do any xml parsing, but instead used string substitution. At first I used xml.dom.minidom, but it seemed needlessly complex for my needs. Maybe that will change.