Champlain Valley water analysis, Spring 2008

As a South Burlington homeowner (water-bill-payer, really), the Champlain Water District sends me a report about how their water is the best water. Of note to me as a homebrewer is the analysis of certain chemical properties of the water. Since a few google searches for this information basically turned up my previous post and not the actual source of the data, here’s the data:

  • aluminum: < 0.06ppm
  • color: 2 units
  • alkalinity: 57-74 ppm as CaCO3
  • calcium hardness: 45-56 ppm as CaCO3
  • total hardness: 61 ppm as CaCO3
  • chloride: 17ppm
  • foaming agents: < 0.1 ppm
  • total organic carbon: 2.04 pm (1.49-2.61)
  • conductivity: 192 micro-S/cm (156-194)
  • pH: 7.62 (7.39-7.79)

  • total disolved solids: 113 ppm

  • iron: < 0.01ppm
  • manganese: .007ppm
  • sodium: 7.5ppm
  • potassium: 1.31 ppm
  • sulfate: 15 ppm
  • silver: < 0.05ppm
  • silica: 1.4ppm
  • silicon: 0.67 ppm
  • bromide: < 0.010 ppm
  • iodide: < 1 ppm
  • flouride: 1.01 ppm (0.74 - 1.28)
  • ammonium ion: 0.15 ppm (0.01 - 0.32)

Champlain Valley water anlysis, 2007

Since the previous water analysis from 2005, I’ve since bought a house, which means the Champlain Water District sends me a report about how their water is the best water. Of note to me as a homebrewer is the analysis of certain chemical properties of the water. Since a few google searches for this information basically turned up my previous post and not the actual source of the data, here’s the data:

  • aluminum: < 0.06ppm
  • color: 2 units
  • alkalinity: 42-56 ppm as CaCO3
  • calcium hardness: 45-56 ppm as CaCO3
  • total hardness: 61 ppm as CaCO3
  • chloride: 17ppm
  • foaming agents: < 0.1 ppm
  • total organic carbon: 2.22 pm (1.60-3.1)
  • conductivity: 189 micro-S/cm (163-208)
  • pH: 7.56 (7.29 - 7.89)
  • total disolved solids: 113 ppm
  • iron: < 0.01ppm
  • manganese: .007ppm
  • sodium: 7.5ppm
  • potassium: 1.31 ppm
  • sulfate: 15 ppm
  • silver: < 0.05ppm
  • silica: 1.4ppm
  • silicon: 0.67 ppm
  • bromide: < 0.010 ppm
  • iodide: < 1 ppm
  • flouride: 0.97 ppm (0.71 - 1.21)
  • ammonium ion: 0.20 ppm (0.04 - 0.048)

java array iteration

Java5 now has language support for iteration of the form:

for (Type var : someIterable) { ... }

As well, there is now an Iterable<t> interface, and Arrays are directly iterable, allowing you to write:

String[] thingys = {"a","b","c"};
for (String thingy : thingys) { ... }

At work, we have a collection of utility iterators, most written before these were available. As such, we have an ArrayIter utility, and a ZipIterator, inspired by Python’s itertools.izip.

I’ve been going through these classes and their usages on a lazy basis to update them to the new syntax. I finally got around to a usage of the ZipIterator, which happened to compose an ArrayIter … it zipped together an array of String names with the results of a test.

So, I changed it to:

String[] names = { "foo", "bar", "baz" };
List results;
for (Object[] pair : new ZipIterator(names, results))
{
// ...

No dice, says Java:

/home/jsled/stuff/work/[...]TestMumble.java:46: cannot find symbol
symbol  : constructor ZipIterator(java.lang.String[],java.util.List)
location: class com.spokesoftware.util.iterator.ZipIterator
for (Object pairObj : new ZipIterator(data, results))

WTF? Okay, let me help you out:

for (Object[] pair : new ZipIterator((Iterable)names, results))
// ...

FUCK YOU, says Java:

/home/jsled/stuff/work/[...]/TestMumble.java:46: inconvertible types
found   : java.lang.String[]
required: java.lang.Iterable
for (Object pairObj : new ZipIterator((Iterable)data, results))

It turns out that the string “iter” isn’t even in the text of the section about Arrays in the Java Language Spec. Array instances aren’t Iterable. They’re a special case in the handling of the for-each loop syntax.

This code ended up as:

for (Object pair : new ZipIterator(Arrays.asList(names), results))

Java is totally shitrude.

rstiki-1.1

Felix Wiemann of docutils was kind enough to write and point out that docutils doesn’t protect against various kinds of malicious markup and content inclusion. He notes that there are a couple of options to prevent such inclusion.

While I don’t intend to use rstiki on a public-facing web server, others might, and docutils makes it very easy to disable such inclusion. So, it does by default, now.

rstiki-1.1 also sports a new link to the rST quickref.

rstiki - minimalist wiki using reStructuredText

I used to use phpwiki for a personal, behind-the-firewall wiki. It was simple, though it was many files, and gentoo packaged it. Then, there was a version upgrade that required a database and lost all my (handful of) content. I switched to pwyky because it was a single file, simple, and SBP wrote it. But its syntax doesn’t support nested lists, and it’s not reStructuredText.

rstiki is a minimalist single-file CGI wiki, in python, which uses docutils to render reStructuredText markup.

wish (x10dev) 2.1.5 ebuild

I got frustrated last week and fixed the wish-2.1.3 ebuild to install the /dev/x10 nodes into /lib/udev/devices/. It was relatively hard to find this out, but when traditional mknod-created nodes are in this directory, they’ll be copied into the otherwise-dynamic /dev tree at boot time. As such, wish finally boots cleanly.

In the course of trying to track down other system lockups, I upgraded to the 2.6.18 kernel, and wish-2.1.3 stopped building for me. A devfs header file that it used was finally deprecated out of the module-building header directory. Luckily, in the mean time, wish-2.1.5 was released without this dependence on devfs. I re-generated the patches, and updated the bug to be an ebuild for wish-2.1.5, a.k.a. x10dev.

Org-mode (vs. planner-mode)

Yesterday I switched from using planner-mode to using Org-Mode, both emacs note-tasking and todo-task management apps. I’ve been using planner-mode for the last year and a half, and rely on it pretty extensively to track upcoming todo items, in both personal and work contexts.

I’ve read in the last couple of months, however, that Org-Mode is already in emacs-cvs, and will be part of the standard distribution of emacs-22. I decided to try it out, was quickly impressed, and transitioned over.

Both support the same basic data model: files of mixed notes and todo-items, where the items are simply specially-formatted lines in the file. Items have an optional due date and an optional priority (ABC). For example, in planner-mode, they appear:

A _ Write up planner-/org-mode post (2006.11.24)

B X Make faux-chicken dinner for Thanksgiving (2006.11.23)

For Org-mode:

** TODO [#A] Write up planner-/org-mode post SCHEDULED: <2006-11-24> ** DONE Make faux-chicken dinner for Thanksgiving SCHEDULED: <2006-11-23> CLOSED: [2006-11-23 Thu]

Both support the same basic execution flow: when requested, the package looks through the special files to find lines that fit the pattern, and constructs another file (planner) or a transient view (Org) over past-due and presently-due items. There are operations for creating items, scheduling them on a particular date, transitioning them closed, jumping from the item to associated notes, &c. As well, both support some form of unidirectional publishing of the content to HTML, ostensibly to serve as some public project-planning status.

Org-mode, I’ve discovered, goes far beyond planner-mode in terms of features.

  • Core
  • It is based on outliner-mode, and its documents are inherently foldable, hierarchical documents.
  • It uses file extension (”.org”) for mode-selection, so planning document can live next-to or within projects.

  • Todo

  • There’s a bit more latitude where items can be placed in the notes documents.
  • It supports — separately from the scheduled to-do time for a task — a deadline, which is brought up differently in the “now” view.
  • Overdue items are indicated more clearly.
  • Items can be scheduled for a range of time.
  • Items can be tagged arbitrarily and searched/viewed by tags (”WORK”, “STORE”, “@LAPTOP”, …)
  • Supports progress logging
  • Supports hierarchical sub-tasks (yay!)

  • Linking

  • Explicit linking rather than CamelCase (though CamelCase is an option), which was the major problem I was having with planner-mode (it starts to become really slow for large documents).
  • Patterned links (”bugs:1234″, “http://bugs/show_bug.cgi?id=%s” → “[…]?id=1234″) are supported.

  • Other

  • Has a table/spreadsheet editor. The table-editing part appears similar to table.el, but the spreadsheet functionality is just pure awesome.

Update Mon 2006-11-27: after being contacted by Carten Dominik, the author of org-mode, I’ve revised the comment at the end about the table/spreadsheet editor.

Oscar handler

Were you the Telepathy project, what would you name your Oscar protocol handler subproject? Why, Wilde, of course. Yuck yuck yuck.

creating many graph instances in cacti

cacti_db.py is a script which will clone an existing data-template and graph-template for multiple (host,rrd_file,template) instances.

In the scenario it was created for, data is (externally) collected into a (directory) tree of RRD files. While there are only a handful of unique RRD file and graph types, there are a large number of instances of those templates. Good examples of this are:

  • cpu load
  • 1,5,15 minute averages
  • 1 per machine
  • disk util
  • avail, used, free
  • ~5 per machine
  • cache stats
  • (hit, miss, size) stats
  • 2 .. 20 caches/”node”, depending type.

This collected data might exist in the following tree of RRD files:

/servers/hostA/cpu.rrd /servers/hostA/disk/root.rrd /servers/hostA/disk/usr.rrd /servers/hostA/disk/data/logs.rrd /node/nodeA/cache/foo.rrd /node/nodeA/cache/bar.rrd […15 more caches…]

Cacti has the following templates manually configured:

/servers//cpu /servers//disk /node/*/_cache

The script, then, knows how to relate RRD files of the regex pattern r'''/servers/([^/]+)/cpu''' to the template(s) “/servers/*/cpu”, using the regexp group 1 as the name of the host; edit the ‘rrd_types‘ global to suit your scenario.

Instances are named as their RRD file name (yes, skipping Cacti’s own |template_formatting|).

The script will delete instances with the same name, allowing you to re-run it pretty liberally to pick up new rrd files, changes in templates, &c.

The process of cloning is as follows; see ‘execute_plan_alpha(...)‘ in the script for the gory details.

  • find the host in table ‘host‘.
  • data template instantiation
  • find the data template id (by name) in ‘data_template‘.
  • if an instance with the name already exists: delete it.
  • insert into data_local, get new (autoinc) id for the instance.
  • get the list of rrd DSes from the template (from ‘data_template_rrd‘)
  • copy each, maintaining the instance -> template id map.
  • instantiate the data_template itself (’data_template_data‘)
  • copy the RRAs as well (’data_template_data_rra‘)
  • graph instantiation
  • get the graph_template_id (by name) from ‘graph_templates
  • insert into ‘graph_local‘, get autoinc id.
  • instantiate graph (’graph_template‘).
  • copy ‘graph_instance_item’s, as this is where the graph-ds/rrd-ds mapping is stored, run the relevant ids through the map retained earlier.

For details on Cacti 0.8’s rather atrocious database schema, see Cacti Forums: Database schema… WTF? and Cacti Forums: Cacti data relationship diagram.

Labor day weekend hardwood floor installation

Ever since buying our home, we have been eager to replace both the (hideous) kitchen and dining room floors. While the dining room floor isn’t nearly as offensive, a couple of the tiles had already come up, and we were pretty lazy in covering it when we re-painted the room, so it was easily a candidate. As well, given that we’ve never installed a floor, and the dining room floor – unlike the kitchen — is basically square, we decided to start with that room to get an idea of the process.

We found a very good guide to installing a hardwood floor, which was quite useful. We certainly bought enough wonderful bamboo wood beforehand, but the tools were generally purchased and rented in the Friday before the weekend. In short, the following were used:

  • pneumatic floor nailer (2: the first one jammed/failed just after the store it was rented from closed for the remainder of the weekend; Home Depot was still open, however)
  • air compressor
  • rubber mallet
  • pry-bar
  • miter box + hand-saw
  • measuring tape, square
  • normal hammer
  • paint scraper
  • finishing nailer

removing tiles

We started pulling up the existing floor on Thursday night with the two tiles that had already come up in the last year … trying to understand how hard that would be. Luckily, the original floor installers had used very little glue. The tiles came up without much effort, and left nothing behind. The sub-floor was in great shape, ready to accept a new floor.

The installer in the aforementioned guide did some nifty drilling to create well-countersunk nail wells and covering plugs for the initial row of flooring. We, uh, didn’t do this. After carefully aligning the first row, we tried in vain to nail some finishing nails straight through, but bamboo is 106% harder than Red Oak, the manufacturer proudly proclaims. At this point, for some reason, we also didn’t have the finishing nailer. So, we used the floor nailer directly applied to the surface, creating some unsightly blisters on the first row. However, that row was now solidly attached to the subfloor. We looked at the remainder of the unfinished floor, and put our first folly behind us.

The remainder of the rows slotted nicely into place. As mentioned, this room is simple, and thus has only 3 widths. As the planks were tounge-in-groove and end-matched, there was some thought-work required to make sure we had the appropriate cuts to create “in-nie” and “out-ie” pieces for the left and right sides as we alternated seams. There was a section where my measurement was a bit off, so we had 2 rows that ended in a 1 inch gap from the wall. We agreed that wide trim would hide a multitude of sins, and pressed on.

We were also lucky in that we only had to cut one (1) notched piece, around one of the heater vent covers. All the other transitions were “perfectly” aligned. There were multiple “will you look at that!” and “my word”. It was good.

Of course, the last row didn’t work quite so nicely, and needed to be “ripped” … as I now understand, a word meaning “to cut a thin piece of wood the long-way”. I started into the short segment with the hand-saw in the basement, but the bamboo – 106% stronger than Red Oak – did not like this idea. As well, just given the geometry of the saw and cutting through a long piece of wood, a saw toothed pattern emerged. We resolved that trim would be our friend, and pressed on. We did, however, call Home Depot to find out that they do in fact cut wood that you do not buy there, as the long segment was forthcoming.

On the 2nd Home Depot trip of that day (after getting the finishing nailer), I found out that they cannot rip pieces unless it’s plywood wider than 12 inches. Dejected, we returned home, having no other option but to saw our arms off.

After returning, and even after starting to saw, we looked for options. We settled on perforating the board with a series of closely-spaced drilled holes, which would reduce the volume of wood by a good fraction … at least half. This actually worked pretty well; at times, the hand saw cut through inches of board as like butter. With the last piece cut, and luckily fitting, we ended the second night with an un-trimmed but finished floor.


When we do the kitchen, we’ll make only a couple of changes: * have the finishing nailer at the beginning * rent a table saw

But, otherwise, we’re looking forward to another nice home improvement project.

And that damn kitchen floor being gone.