Windows dot2tex and exemaker gotchas

Computers, math

This whole post deals with Python 2.7 on Windows. Your mileage may vary in other environments.

I’m doing some writing on the topic of hybrid automata, and it looks like the best way to generate figures of the automata in LaTeX is with GraphViz and the dot2texi package, which works with the very nice dot2tex tool to generate figures from GraphViz dot formatted code embedded directly in LaTeX.

One of the issues, however, is that it expects an executable called “dot2tex” to be available on the shell. This means that, first and foremost, shell escape needs to be enabled when compiling the document (–shell-escape in many distributions, and –enable-write18 in MiKTeX, which I use). Adding this line to the beginning of the LaTeX source will handle it:

%& --shell-escape --enable-write18

Next, since the executable file that’s installed (in Windows on Python 2.7 it goes, by default, to C:\Python27\Scripts\dot2tex) is made executable by a shebang on its first line, even if this file is on your path in Windows, it won’t do anything. So you need to use ExeMaker, which creates a very lightweight exe file to call a Python script. I put it in a directory that’s in my PATH (I made C:\Users\george\bin for this purpose) ran it like this:

C:\Users\george> rename C:\Python27\Scripts\dot2tex dot2tex.py
C:\Users\george> exemaker C:\Python27\Scripts\dot2tex.py

In my case, this created dot2tex.exe and dot2tex.py in C:\Users\george\bin. However, running dot2tex.exe causes an error:

C:\Users\george>dot2tex
Traceback (most recent call last):
  File "C:\Users\george\bin\dot2tex.py", line 6, in <module>
    from dot2tex.dot2tex import main
  File "C:\Users\george\bin\dot2tex.py", line 6, in <module>
    from dot2tex.dot2tex import main
ImportError: No module named dot2tex

A bit of poking around reveals that this is due to the way that Python searches paths in import statements: the script, dot2tex.py, conflicts in its name with the module that we want to import, and the first directory that Python searches when looking for a file to import is the directory containing the executing script (or, in interactive mode, the working directory). The workaround I came up with, which seems to work well, is just to add two lines to dot2tex.py:

import sys
del sys.path[0]

Now my dot2tex.py file (the one in C:\Users\george\bin) looks like this:

#!C:\Python27\python.exe
import site
import sys
del sys.path[0]
#!C:\Python27\python.exe
from dot2tex.dot2tex import main
if __name__ == '__main__':
    main()

So far, this seems to have fixed all of my problems.

No Comments

Lemon-Lime Soda from the Keg (Recipe)

Homebrewing, Kegerator

The Cornelius kegs used by many homebrewers for kegging beer typically started their lives as soda kegs. So there’s no reason they can’t be used for that again in between beers. In fact, the middle tap in our kegerator typically dispenses what we call “lemonade” but what is, in fact, a very flavorful lemon-lime soda (“homemade  7up”).

Here’s the (uncomplicated) recipe for a 5-gallon batch.

  • 1 32 Fl. Oz. bottle of lemon juice
  • 2 15 Fl. Oz. bottles of lime juice
  • About half an ounce of concentrated Stevia sweetener
  • 5 gallons of water
No Comments

Cygwin, Mercurial, and Pageant with Plink

Networking, Programming

If you like to use Cygwin and Mercurial together, like I do, it might be handy to know how to get your Mercurial commands from inside Cygwin to use PuTTY’s Pageant as its agent for SSH keys.  It’s pretty simple, using PuTTY’s Plink. Plink is the PuTTY tool designed for non-interactive ssh usage.

Just add an ssh entry to the [ui] section of your .hgrc file:

[ui]
ssh = "C:/Program Files/PuTTY/plink.exe"
No Comments

The Boolean Algebra of Blood Donation

math

The blood types we usually talk about are determined by the presence or absence of three antigens (A, B, and Rh-D). Here’s a table, where presence of an antigen is denoted by a 1 (true) and absence, by a 0 (false).

A B Rh-D Type
0 0 0 O-
0 0 1 O+
0 1 0 B-
0 1 1 B+
1 0 0 A-
1 0 1 A+
1 1 0 AB-
1 1 1 AB+

You will reject a blood donation if it contains an antigen that your own blood does not. This is why O- is the “universal donor” (none of those antigens to reject) and AB+ is the “universal recipient” (you have them all naturally, so nothing is rejected). Let’s make a truth table for this, just for the A antigen:

Donor A Recipient A Can accept
0 0 1
0 1 1
1 0 0
1 1 1

Does that look familiar? It should; it’s the logical implication operation. So a person can receive another’s blood if the donor’s blood type bitwise implies the recipient’s blood type. Neat.

No Comments

New QuikTrip: The Happiest Place on Earth

Local, Pictures

I hit the 15th and Denver QuikTrip for a late night snack. The new store is open. It’s huge and unbelievably nice. I was in awe, and so were the other customers at the time. I took a couple of photos.

They have a selection of about 8 or so iced teas and multiple choices for lemonades:

I believe they had to invent a dozen new Freezoni flavors for the frozen drink area:

The iced tea center is straight ahead in this view, the frozen drink theme park is to the left; beer is all the way back and to the right, the checkout counter is to the left (you can see the back of the line), and to the right is — I kid you not — the soft serve and coffee shop. You make your selection on a touchscreen kiosk. I don’t know if it’s open 24 hours, but it was definitely staffed at 12:30 AM tonight.

A view from the other side of the store. You can sorta make out the gigantic flat screens that are inset to the wall around the coffee shop counter for some reason.

This place is seriously epic.

4 Comments

Kegerator Build

Beer, Homebrewing, Kegerator

Note: if my blog is running too slow, or you want to see some more photos from the build, check my flickr keezer set.

Inspired by Jester369′s post (among others) on HomeBrewTalk.com detailing their conversion of a chest freezer into a homebrew-appropriate kegerator (or “keezer”) I decided to follow suit. I bought an old, smallish chest freezer off of Craigslist, and eventually Evan (the boyfriend) and I started building it.

Here’s the old freezer, downstairs in the storage unit; photos cannot possibly capture the ugliness of the faux wood plastic lid:

Because the outside was old, unattractive, and the hinge mechanism was old and rusty, we decided to totally remove the top and replace it with a new one that we’d build. Gross, rusty hinges:

The replacement top would need to raise the top of the freezer to give enough clearance for proper operation of the kegs, which are tapped from the top. The common design idiom for this is to build a “collar” to elevate the lid.

Because we trashed the ugly lid and hinges, we opted to mount a mostly-permanent tall box (“coffin”) on the back to provide a mounting point for the faucets, then to put a countertop on the front, which can be lifted off to provide access. Below is an early concept sketch for the top, which gets the point across but doesn’t look a whole lot like the final product:

Sketch of the interface for the outside edges of the countertop to the collar:

This is almost exactly what we wound up doing, except that we decided to hold off on the weatherstripping until we determined it was needed to improve the seal. In fact, it turned out that the panel fit snugly enough onto the collar that the weatherstripping was unnecessary (so we skipped it); however, we did put some strips of felt where the countertop meets the coffin to provide some “give”.

Also, the part labeled “cutting board” reflects my original desire to use  butcher block for the countertop, though it wound up being orders of magnitude cheaper to go with tile.

One last sketch before the actual photos from the build; this one is my proof-of-concept in determining what, exactly, I could fit in the compartment. Ultimately I decided to fix the number of taps at 3, which provides some wiggle room to clean up spills and condensation, as well as providing room for several six-packs (or, in practice, anything else that overflows from our main refrigerator). One grid unit is one inch:

All right! On to the build. So the first thing we did was pack the thing in my hatchback, drive it to Evan’s work, and strip all the crap off: We removed the lid, the hinges, and the top layer of the paint:

Then it was black Rustoleum Appliance Epoxy to turn it the color we wanted:

a

Next, we learned the wrong way to build the collar: using right angle brackets and screws. The result was not quite square anywhere and, more importantly, not flat anywhere. Browsing other folks’ writeups of their builds, I found that I was not the first person to learn that this is the wrong way to build a collar. If you’re doing a build yourself, do not use angle brackets to square your collar.

What, you ask, is the correct way to build a collar? Glad you asked. It involves right-angle clamps (the link is to Amazon, though I got mine, a different brand, from Home Depot), which were a bit on the expensive side but easily the second most valuable tool in the entire process. I wish I’d bought eight of them instead of two.

This leads me into the most valuable tool in the entire process: the nail gun. The correct way to build the collar is to clamp the thing together, square and level, then nail or brad it together. After doing that, we used those angle brackets for reinforcement.

All the pieces, plus the fridge, crammed into the back of my little hatchback (VW Rabbit):

Here it is, clamped together for an in-progress glamor shot in the corner of the apartment for which it is ultimately destined:

Here’s a photo of the assembled “coffin” (where the faucets will live) — nailed together and soon-to-be bracket-reinforced, all with the aid of the right-angle clamp again.

Here’s the base for the countertop, assembled and stained; this is the part that will be removable for access to the fridge compartment; you’re seeing it from the top-down here:

Three screws in each corner of the plywood board so it’ll support all the glasses you’d ever want to fill:

Ignoring the mess in the visible area of the apartment, here’s the product of Evan’s first-ever tiling job, prior to removing the leftover grout. Not too shabby:

This interfaces to the collar in two ways; the 1×4 border rests on the top of the collar, and the board under the tile rests on a 1×2 support glued and screwed into the inside of the collar, pictured below:

Here’s a view of the assembled product so far; all we’re really missing is the faucets and insulation:

Since we removed the original lid and the plastic seal around the top, we needed a way to cover up the exposed insulation. I had some plexiglass sitting around and decided to cut it to size and seal it with silicone. Here’s one of the joints, in progress:

To provide extra insulation, we used three-quarters-inch styrofoam insulation, doubled-up in many places; we wrapped it in heavy-duty aluminum foil to keep it all together:

The top insulation piece (pictured below) is separate from the countertop piece; this makes opening the fridge a two-step procedure but reduces the risk of knocking the insulation off:

Okay, so now that the insulation’s out of the way, the only thing left is to attach the faucets. Evan insisted that we put some kind of design behind the faucets; I finally agreed (and am glad I did!). We found a little bit of spare sheet metal and cut it into three three-tiered designs, each of which looks a little bit like this (from behind):

Three of these attached to the front of the “coffin” look like this (after punching big holes in each of them, which, I’ll note, was a bit of a pain):

After the fact, we noticed (and were not bothered in the least) that we had basically ripped off our apartment complex‘s logo (this design is on every elevator landing in the building):

A bottom-up view of the “coffin” piece with the bottom cut out, shanks and backing pieces attached, and insulation visible (plus the crown molding has been stained):

Here’s the completed view of the top of the keezer, with the default black plastic handles on each of the faucets. Note also the Reddit alien, which is just waiting for a hole to be drilled in the bottom to attach to the rightmost faucet, which is to dispense “/r/paleale”, my entry to the Reddit Homebrewing Competition in the American Pale Ale category.

Okay, so, all of that said; how am I to keep my chest freezer from turning my beer into slushies? With a new thermostat! I don’t need to replace any part of the freezer, of course, because it wants to take its contents down to 0°F. So I just kill the AC power to the freezer when it gets to the temperature I want it to be.

Lots of people use a “Johnson” for this. I thought $75 was a bit steep, so I built my own out of an Arduino Pro Mini (Sparkfun’s miniaturized, cheap Arduino variant), digital temperature sensor (that looks an awful lot like a transistor), and a relay control board for closer to $30.

Incidentally, I did accidentally slushify a keg of beer a couple of weeks ago; it was pretty much hilarious.

Here’s the assembled relay control board in an enclosure with AC in and out (on the right) and the VCC, ground, and control line for the relay (left):

Here’s the Arduino mounted on a piece of protoboard I had sitting around. The wires going toward the top connect to the temperature sensor. Not pictured (and still not connected, though it is built) is my display PCB.

That’s it! Here’s the finished product at the time of activation:

Plus a bonus photo of the completed /r/paleale handle:

3 Comments

Vulnerable Code: MoinMoin User

Programming

I’ve just started posting code samples from the wonderful SpotTheVuln.com on the walls in our building on 11×17 cardstock behind thin plexiglass panes so they can be annotated with dry erase marker when people solve them or have comments:

I love the site but wanted to branch out a little bit into some samples outside of the PHP and WordPress world. In my first attempt, I didn’t branch very far, and it’s a bit longer than I would have preferred, but here it is — from MoinMoin. Hopefully I included enough information to find the issue.

def getUserId(request, searchName):
    """
    Get the user ID for a specific user NAME.
 
    @param searchName: the user name to look up
    @rtype: string
    @return: the corresponding user ID or None
    """
    if not searchName:
        return None
    cfg = request.cfg
    try:
        _name2id = cfg._name2id
    except AttributeError:
        arena = 'user'
        key = 'name2id'
        cache = caching.CacheEntry(request, arena, key)
        try:
            _name2id = pickle.loads(cache.content())
        except (pickle.UnpicklingError, IOError, EOFError, ValueError):
            _name2id = {}
        cfg._name2id = _name2id
    id = _name2id.get(searchName, None)
    if id is None:
        for userid in getUserList(request):
            name = User(request, id=userid).name
            _name2id[name] = userid
        cfg._name2id = _name2id
        arena = 'user'
        key = 'name2id'
        cache = caching.CacheEntry(request, arena, key)
        cache.update(pickle.dumps(_name2id, PICKLE_PROTOCOL))
        id = _name2id.get(searchName, None)
    return id
 
class User:
    """A MoinMoin User"""
 
    def __init__(self, request, id=None, name="", password=None,
                 auth_username="", **kw):
        """ Initialize User object
 
        @param request: the request object
        @param id: (optional) user ID
        @param name: (optional) user name
        @param password: (optional) user password (unicode)
        @param auth_username: (optional) already authenticated user name
                              (e.g. when using http basic auth) (unicode)"""
        self._cfg = request.cfg
        self.valid = 0
        self.trusted = 0
        self.id = id
        self.auth_username = auth_username
        self.auth_method = kw.get('auth_method', 'internal')
        self.auth_attribs = kw.get('auth_attribs', ())
 
        # we got an already authenticated username:
        check_pass = 0
        if not self.id and self.auth_username:
            self.id = getUserId(request, self.auth_username)
            if not password is None:
                check_pass = 1
        if self.id:
            self.load_from_id(check_pass)
            if self.name == self.auth_username:
                self.trusted = 1
        elif self.name:
            self.id = getUserId(self._request, self.name)
            if self.id:
                self.load_from_id(1)
            else:
                self.id = self.make_id()
        else:
            self.id = self.make_id()
 
    def __filename(self):
        """ Get filename of the user's file on disk
        @rtype: string
        @return: full path and filename of user account file
        """
        return os.path.join(self._cfg.user_dir, self.id or "...NONE...")
 
    def save(self):
        """ Save user account data to user account file on disk.
 
        This saves all member variables, except "id" and "valid" and
        those starting with an underscore.
        """
        if not self.id:
            return
 
        user_dir = self._cfg.user_dir
        filesys.makeDirs(user_dir)
 
        self.last_saved = str(time.time())
 
        data = codecs.open(self.__filename(), "w", config.charset)
        data.write("# Data saved '%s' for id '%s'\n" % (
            time.strftime(self._cfg.datetime_fmt, time.localtime(time.time())),
            self.id))
        attrs = vars(self).items()
        attrs.sort()
        for key, value in attrs:
            if key not in self._cfg.user_transient_fields and key[0] != '_':
                # Encode list values
                if key in ['quicklinks', 'subscribed_pages']:
                    value = encodeList(value)
                line = u"%s=%s\n" % (key, unicode(value))
                data.write(line)
        data.close()
 
        if not self.disabled:
            self.valid = 1
No Comments

Comments Now Support SexpCode

Computers

Koen Crolla has specified a replacement for BBCode (that atrocious square-bracketed markup language for bulletin boards) called SexpCode. It uses S-expressions (think the LISP language), with ‘staches instead of the usual parentheses . Comments in this blog are now SexpCode-enabled.

The source for my comment below is {b This} is {i {u my} {o playing} with} {code SexpCode}.

4 Comments

Java is not Python and Cygwin is not Linux

Programming

I’m burning the midnight oil working on a project in Java and came upon a number of gripes, all right in a row, that I thought were all worth blogging about in case I can help make somebody else’s night a little bit better. So here are some things I learned today.

Java is not Python. Java’s changes that introduced generics (to allow expressions like, for example, “Vector<Integer>”) were pretty much all in the compiler. The bytecode stays the same; the compiler just gets some additional data to use for typechecking. Then your beautifully generic Java 5.0 code undergoes a process called type erasure producing the same — but better typechecked — bytecode that your old 1.4 code would have. The result is that when I, with my limited understanding of Java generics, tried to write overly dynamic code, the compiler scoffed.

“required: class or array”, it said. What it really meant was, “You can’t use a generic type in an instanceof operation, you dummy, because I’m about to erase that type and replace it with Object.” Doi.

Cygwin is not Linux. Especially where Java is concerned. I spent about 20 minutes trying to figure out why I couldn’t pass the JDK an absolute classpath from Cygwin when relative classpaths worked just fine. It was because the JDK I was calling is Windows native, not Cygwin, so it doesn’t understand the Unix-style directory structure I was giving it.

Java is not Python (redux). I’ve mostly been using Python for my various and sundry programming needs over the past couple of years. And it’s impressive how quickly one gets used to a REPL (read-eval-print-loop) — and how useful it is for quick debugging and answers.

For instance, I missed having a REPL when I had a simple question: can I typecast null to whatever object type I want (the answer is yes, by the way, which makes a lot of sense when you think about it)? I was in the midst of a fairly significant rewrite so I couldn’t just try it and run it. So I saw four choices: assume it would work and test it later, assume it wouldn’t work and rewrite it, look it up, or write a Java program to test it.

Turns out that there’s actually a fifth option: use the Java REPL. It’s called BeanShell (or bsh), and I feel pretty much ridiculous for not having found it before. Maybe you’ll enjoy it.

Okay, back to work.

No Comments

New Beer In Primary Fermentation: Untitled Pale Ale

Beer

In concert with my upcoming kegging setup, I’ve just brewed the beer that ought to be my first kegged beer. I’m also aiming to enter it in the Reddit Homebrewing Competition.

It’s pretty straightforward and virtually all extract, but that’s fine with me. I made a couple of weird decisions, namely the darkness of the crystal malt. I’m a little concerned about how dark it’s looking in primary at the moment — I know, I know, what did I expect from crystal 120L? — though the photo makes it look a lot darker than it actually is.

I’m also worried I went too far with the hops, but I suppose we’ll see what we see. I have some hophead friends. As they say: don’t worry, relax, have a homebrew. And I plan to.

I’ll name it once I’ve tasted it.

Untitled “Pale” Ale
Recipe Reddit Pale Ale Style American Pale Ale
Brewer George Louthan Batch 5.00 gal
Extract

Recipe Characteristics

Recipe Gravity 1.048 OG Estimated FG 1.012 FG
Recipe Bitterness 36 IBU Alcohol by Volume 4.7%
Recipe Color 12° SRM Alcohol by Weight 3.7%

Ingredients

Quantity Grain Type Use
1.00 lb Breiss Bavarian Wheat DME Extract Extract
5.00 lb Breiss Pilsen Light DME Extract Extract
0.50 lb CaraPils Grain Steeped
0.50 lb Crystal 120L Grain Steeped
Quantity Hop Type Time
0.75 oz Cascade Pellet 5 minutes
1.25 oz Cascade Pellet 30 minutes
1.00 oz Hallertauer Pellet 60 minutes
Quantity Misc Notes

Recipe Notes

Steep specialty grains for 30 minutes at 155F.

60 minute boil.

Batch Notes

Hops added directly to boil and strained out with a kitchen strainer when transferring to primary. Some remain, which should contribute something like a dry hopping effect; I’ll rack off of the settled hop fragments into secondary and probably filter more efficiently then, as well.

No Comments
« Older Posts