ZigZag fanny test #1

It’s been a while since my last update; I’ve been traveling, and I hit some snags in the production line. It turned out that the clever joint I created just wasn’t going to work, and I decided I really did need to bolt the acutely-angled zigzag joints, as shown in the first fully assembled chair below.

the first chair assembled dry

the first chair assembled dry

In this view the pieces have been trimmed to their final dimensions. Here we can see the chair’s graceful proportions. It spreads out towards the knee and gathers itself in at the waist and heel.

fully assembled and glued, but still unfinished

fully assembled and glued, but still unfinished

Unfortunately, there is just a bit too much spring in the joints, and they creak ominously. I’ll need to brace the zigzags a little more stiffly by increasing the size of the triangle in the joints.

All seated

Finished up the joints for the remaining seats this weekend. Ellen didn’t think I was giving an honest portrayal of the working conditions in my shop, so here’s a full view, showing all eight seats in situ.

what a mess

what a mess

I’m relieved to have finished these joints, probably one of the more exacting tasks in this project. The joints came out pretty well, with only some small gaps (< 1/32") visible on the exterior. I should be able to close most of those up with a little more filing and chiseling, but for now I want to move on to something else. Next up: I have a mind to try a pair of sliding dovetails inside the acute bends.

first few joints

I forgot to post these awesome photos of the zigzag bevels from a few weeks back. It was a joy cutting them with a new supersmooth sawblade with lots of teeth.

tablesaw setup for cutting zigzag bevels

tablesaw setup for cutting zigzag bevels

The clamps hold the piece tight to a board that slides along the saw’s fence. Without this only a tiny edge would be riding on the surface of the saw. The orange plastic thing holds the piece being cut securely against that arrangement, helping to make sure the cuts come out straight and even.

all 22º zigzag bevels cut

all 22º zigzag bevels cut

The setup I made for cutting the dovetail coves wasn’t enough to cut the needed space in a single cut. Now I need to do another pass over them in order to get them deep enough and to cut the insides at the 8 degree angle needed to lean the backs.

IMG_0333

Notice how the board clamped to the front side is angled. The router base will rest on it and cut at the same angle inside the joint.

router with fence

router with fence

finishing up the dovetail coves

finishing up the dovetail coves

The router is an awesome, powerful tool that can make cove cuts that can’t be done with a saw. In the old days, you would use a some combination of saw & drill (auger, gimlet) to get rid of as much stock as possible and then finish up the edges with a chisel. The router gets much closer to the edges of the joint, but it still leaves rounded corners. For the final cleanup and fitting, we need the chisel and file.

hand tools

hand tools

The first of the tails, marked up and ready to be cut. I tried doing this free-hand with the router, but discovered it was too hard to cut a clean, straight line. For the rest, I’ll use the saw to cut along the marked lines before cleaning out the waste with the router. This will also help prevent me from ripping the veneer facing off a large section of the plywood.

marking the tails

marking the tails

Here you can see the surface torn out from one the tails cut before I outlined the tails with the handsaw. Thankfully it’ll be under the seat.

dovetail back side showing grain tearout (oops!)

dovetail back side showing grain tearout (oops!)

This one’s neater.

dovetail back side

dovetail back side

Our first seats! It’s so satisfying when the joints come together.

first seats joined

first seats joined

half-blind compound dovetail

Just a quick update on my progress; I bought myself a new 1/2″ dovetail router bit ($20), and got to work cutting the joints. Almost half the time spent planning, setting up, and cutting tests. The first picture below shows the setup:

Setup for cutting dovetails

Setup for cutting dovetails

In the next picture you can see the results of a few hours at the router table cutting the half-blind dovetail coves in the backs. Notice how the coves don’t pass all the way through the boards: that’s the half-blind part. Initially I had hoped to place the cuts in identical locations on all the backs so that the tail half of the joints could be cut all in one pass, across all the seats at once. Alas, I don’t think that’s to be. There was just too much variability in my setup, even with the nifty jig.

stack of chair backs with dovetail coves cut

stack of chair backs with dovetail coves cut

Next I’ll need to clean up the backs of the coves to make them square with the surface, and chisel out the rounded corners. Then bevel the ends (8 degrees, remember?) cut the tails, and of course the joints will slide together neatly on the first try!

zigzag chairs

Zig-Zag chair

example of a Zig-Zag chair

Some friends (well, one friend) expressed some interest in the chair project I crowed about on facebook recently. So I decided to document the project here. The idea of making a Rietveld Zig-Zag chair was my father’s: he conceived a desire for one, and bought some books and plans. I think he was attracted by the idea that he could make it himself, but eventually abandoned that plan, and sent it to me. In fact the design is deceptively simple: it was described by Dutch designer Gerrit Rietveld in 1934 as a “plane zigzagging through space.” My father wanted a single chair. I looked at the plans and photos, and I realized this would be more than an afternoon’s work. An interesting project, but I had lot of interesting projects at the time, so I put it away.

When I finally came back to the project a few weeks ago, and looked more seriously at the design, I realized that making just a single chair of this type would involve a great deal of wasted effort. The chair’s construction involves several tricky features that belie its simple appearance. Setting up the cutting jigs for these angled cuts and joinery takes time, exacting measurement and careful planning, but the cutting itself is mere rote work: satisfying, easy work on a modern machine.

Furthermore, it was clear from looking at them that Rietveld’s designs were always intended to be mass-produced, and a little reading lends some credibility to this as an accepted historical idea. It is tempting to read the De Stijl movement’s obsession with right angles and rectangles as an embrace of industrial methods. Of course it’s difficult to know: there was a natural reaction against the earlier prevailing Impressionist style, and it may simply be that Rietveld saw an opportunity to capitalize on the style’s suitability for factory manufacturing techniques.

At any rate, I determined to make a set of eight. In this way I could achieve economy of scale by reusing the various table saw and other cutting jig setups I would need to make.

Chief among the difficulties with this chair are the two acutely-angled joints connecting the diagonal member, the “leg” if you will, with the seat and with the base. Usually in finer woodworking one joins pieces without nails, bolts or other hardware, ideally holding them together without even glue. But there really is no classical all-wood joint for the zigzag chair’s acute angles, at least not anything that would support a person’s weight. Classic zigzag chairs use bolts to hold together the two acutely-angled joints. Bolts! I never dreamed of holding together furniture with bolts. I consider using bolts and hiding them, but I don’t particularly like the idea of this kind of subterfuge. At any rate it would be impossible to truly hide the necessary plugs since their grain wouldn’t match. Still we might come up with some other solution.

The other challenging piece of joinery comes between the seat and back. Dovetail joints are called for here: these are the strongest joint for a right angle between boards. Cutting dovetails requires a certain finesse and careful craft with hand tools, or specialized cutting elements for machine tools. I resolved to acquire a dovetail bit for my router that would make it easier to cut the 40-odd tails in these eight chairs. But the back is not at a right angle to the seat. It reclines by 8°, accommodating the human form in a necessary compromise with the purity of the De Stijl movement’s Cubist-informed aesthetic. The resulting joints will have to be cut at an angle 8° from square, forming a mind-bending three dimensional puzzle that I struggle to visualize even with the aid of drawings.

Finally, I complicated the picture a bit further by the use of plywood. Plywood is not often used in fine furniture, but I felt that it was an attractive choice for this project for several reasons. For one, fine plywoods are available (not at all like the construction-grade kind you see at home improvement megastores), and these offer a surface with a large swath of continuous grain. To achieve a similar effect with solid wood would require very wide boards that are not easy to find. Also, I wanted a fine-grained appearance that would require quarter-sawn lumber, a wasteful luxurious product that is almost vanished in this time of scarcer forest resources. I simply felt the idea of using an economical material like plywood would fit better with the industrial aesthetic of the chair design. And finally manufactured boards (plywood) are greener: they make the most efficient use of trees since they are able to use junkier wood on the inside, and save the good pieces for the surface.

The problem with plywood is that its end grain is really unattractive, and tends to get uglier still as it loses little chips during the construction process. The usual technique for dealing with this is to cover the ends with thin strips of solid wood, or veneer, but there was one place on the chair where this technique would not work: the back/seat joint. So I’ve resolved to further complicate the construction of that joint by making it half-blind: the ends of the seat tails will be buried in the interior of the joint, allowing the exterior surface of the back to descend uninterrupted to the outside of the angle with the seat. We’ll see how I manage that as the work unfolds!

Next time: half-blind compound dovetail

Dumping register.com

I recently registered luxdb.org with register.com. Why? It was cheap. Lesson learned (again) – there’s always a reason for cheap. I eventually decided to consolidate this domain with some others I have registered at dyn.com (an excellent provider). When I tried to transfer, I found out you need an authorization code to effect the transfer. Makes sense – keeps people from stealing your valuable domain. The thing is, register.com has instituted a 4-5 day delay before they will send you the code, and even then, they may decide not to send it to you (if they believe there has been “suspicious” activity related to your domain). On the face of it, there might be some idea that they are acting on the customer’s behalf, but based on a cursory read of various angry posters to online forums, and on my experience, it seems pretty clear they are abusing this policy in order to try to prevent customers from leaving.

When I requested the auth code and saw the notice of the 4-5 day delay, I called customer service. I had to hold for 10 minutes, and then for another 5 minutes after I demanded the auth code from customer service (I was a bit peeved at this point), but eventually he did come through with the code, no questions asked. OK, fair enough – it was a little annoying, but I got what I wanted, gave the code to dyn.com and initiated the transfer. That completed after 3 days or so. The funny part is that the very next day I received this e-mail from register.com:

Dear Michael Sokolov,

You recently requested an auth code to transfer your “luxdb.org” domain name.
Your request has been processed and at this time it has been declined due to recent suspicious activity in your account.

Register.com is committed to providing the most secure and reliable domain services for our customers.
We have implemented specific security measures to help prevent unauthorized transfer of domains to another registrar.
The type of suspicious activity that could have caused your request to be declined includes:
– Multiple failed attempts to login to customer’s account
– Recent changes to the account holder’s name, email address, or login ID
– Attempts to access the account over the phone without authorization
– Recent changes to the accounts password
– Domain name lock not removed
– Recent changes to billing or credit card information

To receive your auth code, please call one of our customer service consultants at 1.888.734.4783. They will confirm you to the account and then fulfill your request.

Thank You,

Sandy Ross
EVP, Customer Service
Register.com

Here is my reply:

I hate to tell you this (actually it gives me a dirty pleasure), but you guys are morons. Your policy of delay and obfuscation is insulting and is probably losing you many more customers than it retains. Or maybe you’d rather be the company that serves the feeble and ill-informed. Anyway the transfer is already complete, so not only is this message an insulting lie, but it is completely null and ineffectual.

Very sincerely yours, a happily departed customer,

Mike Sokolov

Multithreaded testing with JUnit

This post demonstrates an easy way to test the effect of multiple concurrent threads running your software, using your existing unit tests.

Have you ever wondered whether your software is really thread safe? Whether it will stand up to the punishment of thousands of concurrent users when your site (or app) goes ballistic? Multi-threaded programming is notoriously difficult, and running software in a environment (like a web application server) that spawns multiple threads can often expose architectural problems that don’t arise in typical test scenarios. Running a set of tests in parallel is a good way to gain confidence that your code is thread safe.

Another benefit of running multiple tests at once is: they run faster! All modern computers have multiple cores, and many have multiple CPUs: when we run our tests single-threaded, we aren’t making use of all of that latent power we have just lying around.

Let’s say you have a test class called MyTestClass, and it defines a number of tests. Using the test runner we provide, you can run all of its tests in parallel by adding a single annotation (the standard org.junit.runner.RunWith annotation that comes with JUnit) to your class:

@RunWith (MultiThreadedRunner.class)

This runner plugs in to the JUnit framework by subclassing BlockJUnit4ClassRunner; this is the class that usually runs all tests from a test class. The runChild() method is called for each test that is run; we take that over and arrange for each test to run in its own thread. We also want to ensure that not too many threads run at once: each thread consumes memory, and, depending on the size of the test class, we may end up running hundreds of threads at once if we’re not careful, and run out of memory. Here is the code for runChild, which simply waits until there are fewer than maxThreads tests running, and then creates a Runnable called Test which actually runs the test:

    protected void runChild(final FrameworkMethod method, final RunNotifier notifier) {
        while (numThreads.get() > maxThreads) {
            try {
                Thread.sleep(25);
            } catch (InterruptedException e) {
                System.err.println ("Interrupted: " + method.getName());
                e.printStackTrace();
                return; // The user may have interrupted us; this won't happen normally
            }
        }
        new Thread (new Test(method, notifier)).start();
    }
 

Note that we keep track of the number of threads in a variable called numThreads. That is an AtomicInteger, which is a thread-safe primitive built into the standard JRE. We use it to ensure that the thread count isn’t updated simultaneously in two threads. Here is the core of the code for the Test class:

        public void run () {
            numThreads.incrementAndGet();
            MultiThreadedRunner.super.runChild(method, notifier);
            numThreads.decrementAndGet();
        }

All this does is keep track of the number of running threads. I haven’t shown the constructor and members used to track the test method and notifier, but as you can imagine, that is just straightforward copying of variables.

The only slight complication with using the code as shown so far is that JUnit will finish before all the tests do. It’s necessary to make the “outer loop” in the test runner wait until the last test has completed before it exits. Usually this happens implicitly, because tests are all run in the same thread, but now, when the runner starts a test, it returns immediately, while the test is still running. To solve this problem, we need to override the childrenInvoker method.

protected Statement childrenInvoker(final RunNotifier notifier) {
        return new Statement() {
            public void evaluate() throws Throwable {
                MultiThreadedRunner.super.childrenInvoker(notifier).evaluate();
                // wait for all child threads (tests) to complete
                while (numThreads.get() > 0) {
                    Thread.sleep(25);
                }
            }
        };
    }

Couldn’t be simpler: just call the super method to do all the real work, and then wait until there are no more test threads running before returning. Does anybody see the potential race condition here? It’s possible that when the last test is run, childrenInvoker will return and test numThreads before that last test has a chance to increment it. In practice this doesn’t seem to happen since there will generally be several threads running already when the last test is started, but just to be safe, it is better to increment the threadCount in the main runner thread, just before calling Thread.start(), and then to decrement it in the child thread, just before exiting. The attached file has that change.

Download the source code here:
MultiThreadedRunner

Note that this code is distributed under the Mozilla Public License (2.0), which basically says you can use this code freely, embed it in your software, and even redistribute it, as long as it retains its license and attribution (includes the comments it has now saying who wrote it), and as long as any changes you make to the software are distributed under the same terms: also I encourage you to post any changes you make here so I can incorporate them.

linux firefox ipv6 snafu: FIXED!

I post this in the hope that it will save someone the headaches I suffered:

I found that certain web sites were unusable (super slow – minutes to load) in firefox on linux, although retrieving pages from the command line w/say wget worked just fine – python.org, for example, and the firefox addons site. It turns out that DNS records for these sites include ipv6 addresses, and I guess we can’t route ipv6 packets properly? I was able to fix the problem by disabling ipv6 on my box:

in /etc/modprobe.d/blacklist I added
blacklist ipv6

a foot of water in the well

Like many of my neighbors, I came home to a basement full of water last night. First thoughts – all the stuff that would be ruined; we quickly abandoned the pile of childcraft books, the old rugs, some boxes of breakfast cereal that hadn’t been put away yet. But my tools, some lumber, the leaf for the dining room table: it would be a shame if they were destroyed. We lifted them up out of the drink onto plastic tubs, tables, whatever. Later we’d assess the damage.

Then, a bucket brigade. My girls chipped in mightily: one in the basement, filling buckets with a bailer from the boat; one carrying up the stairs, and I was the anchor leg, carrying and heaving out into the street, while it continued to rain and sleet.

Finally the water was down to the well: a little-used foot-deep pit in the basement where the sewer pipe can just be seen poking up from the surrounding dirt. “Just five more minutes, girls!” I encouraged them. We got the water down about six inches. OK, time to eat some hot stew.

Sadly, after dinner, we found the water had risen almost to the top of the well again. Calls to all the late-night, big-box, home improvement stores were met with “Hello, this is Home Depot. We are all out of sump pumps, in Massachusetts, Rhode Island and New Hampshire.” I guess we weren’t the only ones. I pressed a little electric pump from the dehumidifier into service; it produced a thin flow, but seemed to be just holding its own: the water level held.

Update: this morning the weather is fine: sunny and dry. The water is receding. Time to begin the cleanup!

Balisage 2009 trip report

Balisage (once Extreme markup) seems to be the Summer conference of choice for schema architects, developers, visionaries and markup philosophers: in short, those laboring on the underpinnings of XML and related technologies. Conference literature calls us “markup geeks.” Mere users of these technologies might find this conference heavy sledding (it is quite technical), and marketers should be aware that this is not a trade show: there are few opportunities for promoting goods and services. However, idea-pushers will find a welcoming audience at Balisage.

This year, I attended Balisage for the first time, and I found it a highly rewarding experience. I came away full of ideas for new ways to work, new tools to use, and new directions in which to push our XML-based publishing practice. In addition I made a passel of new friends: The community that has grown up around this conference is very welcoming, and surprisingly so, given how close-knit it seems to be. The conference is well-organized and run by folks from Mulberry Technologies and friends, with a wide array of reviewers vetting papers and presentations. My one complaint is that I was unable to remain for the full schedule and missed some very exciting-looking presentations on Thursday and Friday.

Disclaimer: I was unable to see every talk, so this report represents merely some highlights, as I saw them. This report is biased and unfair, but honest and without the intention of brutality.

Day 1

On Monday, Michael Kay of Saxonica chaired the Symposium on Processing XML Efficiently, a separate but related series of presentations that shared the same logistical backbone with the main Balisage conference.

The surprise hit of this session was Rob Cameron’s presentation on Parallel Bit Stream Technology. At first, I had no clue what was going on in this talk. The basic idea seemed clever: rotate your bytes sideways, packing all the first bits into a wide (64-bit or wider) word, all the second bits into the next word, and so on. But what was the point? When Cameron demonstrated that some simple addition and shifting operations led to a bit pattern that encoded the positions of all the valid XML numeric entities, the “aah” of dawning comprehension rippled through the audience. He went on to show how this could be used to jump-start a tokenizer and accelerate XML parsing, resulting in impressive speedups in a core technology. There are some remaining challenges, though: to make these results available via Java will require some tricky bridgework.

I was curious to hear about the internals of our competitor, Highwire’s, much-ballyhooed H2O platform, presented by James Robinson. Given the context of the conference, it was no big surprise that the workhorse of H2O (Firenze) is an XSLT-based rendering pipeline with built-in caching features. What was most interesting was what it’s not built on top of: a database. The core storage mechanism of the public-facing content delivery system is essentially a hierarchical file-system store. Search features are provided by FAST, (acquired last year by Microsoft). Some interesting observations:

  1. The use of XML data and processing models in every step introduced some overhead (for example, performing HEAD requests that check the cache went through an inefficient XSLT and consumed 30% of overall execution time). Resolving these performance bottlenecks requires some special attention and custom optimizations. However, Robinson felt such costs to be outweighed by the benefit of the more convenient programming model.
  2. The LRU cache was distorted by search engine crawlers, which tend to perform broader-spectrum requests than typical users. Robinson plans to optimize for human users by introducing an ARC cache, which will take into account the frequency of requests for a given resource when aging cache entries.

David Lee presented a performance comparison of various scripting techniques for running multi-step XML pipelines. The resulting comparison of xmlsh and xproc, which run xml processes internally, with shell scripts which execute xslt and xquery externally, was largely a cautionary tale about the cost of repeatedly starting and stopping the Java VM. Although this wasn’t news to many attendees, it is the kind of implementation mistake that is easy to make even if one’s theoretically aware of the issue. The talk was also valuable as an introduction to xmlsh and xproc, two scripting technologies that ought to be in every XML-hacker’s toolbelt. Lee developed xmlsh, an XML scripting language with syntax based on Unix shell; XProc is a nascent W3C standard with a few available implementations, including Norm Walsh’s Calabash, which was tested as part of this work.

Balisage, Day 1

After some introductions, Tommie Usdin launched the conference with a dose of tart wisdom. She issued cautions about blind adherence to standards, urging a deeper understanding of requirements. The rest of the conference was peppered with mild disagreement with her plenary point: Standards considered harmful.

Alex Milowski reminded us that Netscape has had sophisticated XML support in the browser since 1999, although the lack of comparable support in Internet Explorer was treated as a minor, if unfortunate, side note. Milowski made a plea for a core set of XML vocabularies including HTML, SVG and MathML. He then demonstrated some pioneering work with audio-enabled eBooks (in the DAISY format) using Firefox extensions, and indicated a similar model is also available in the mobile space (using iPhone and Android). What I learned: you can associate MIME types with Firefox plugins so as to trigger custom behavior for your content type.

Somehow I managed to miss David Birnbaum’s talk on writing optimal XPath and XQuery for eXist’s evaluation engine, which I had intended to see. I guess I’ll have to read his paper when it’s posted. I also sadly missed seeing Michael Sperberg-McQueen’s talks, which, to judge from the questions with which he prodded the speakers, would have been fascinating.

Uche Ogbuji presented his application development platform, Akara, which integrates XML-native operations with Python in clever ways. Python developers working with XML will want to stay abreast of this work from the former developer of the 4Suite toolset, currently available in Beta.

To wrap up the first day, we had to choose between a fascinating-sounding flight into abstraction from Wendell Piez, and a survey of XML visualization tools from Mohammed Zergaoui. In the end, my practical orientation won out, and I was rewarded with a number of links to follow. In particular I am intrigued by Xopus, an in-browser WYSIWYG XML editor that looks very promising. I got a demo at the conference (from Betty Harvey), and will definitely follow up since this is something we need to embed in our solutions. I still wonder what a “nomic game” is, though.

Day 2

Fabio Vitali presented a new approach to handling overlapping markup. I learned that this is a major area of theoretical interest in markup that has been addressed by numerous proposed schemes. XML’s element tree can’t represent overlap directly in a natural way, and markup such as bold, italic is inherently ambiguous (which tag should be the outer one?). Although new to me, this seemed to be well-trodden ground for many at the conference, and the new contribution was the idea of using RDF and OWL as representation meta-languages.

Norman Walsh shared some data gathered from the “phone home” feature of XML Calabash, his XProc implementation. Every time Calabash runs, it sends some basic profiling information to xmlcalabash.org, unless the user explicitly opts out. Some insights: it appears that many (most) pipelines are streamable, at least from the viewpoint of XProc, although it was less clear what the benefit of streaming might be in these cases. One odd feature of Walsh’s data was that a surpriing number of pipelines have only a single step in them; he attributed this to the convenience of executing other XML processes via XProc, or possibly to a pattern of tire-kicking behavior.

The final regularly-scheduled presentation was Michael Kay’s discussion of the polarity of streaming processes. This included a fascinating discursion on the merits of co-routines for programming inherently multi-processing programs; their performance benefits relative to multi-threading; the difficulty of implementation in single-stack languages such as Java. Remarkably, there was a dearth of questions after Kay’s presentation. This was not a case of lack of interest; rather it seemed as if all the bases had been covered, and in the end there was just nothing more to be said once the master had spoken.

After a deeper dive into eBook formats with Alex Milowski, and a presentation on REST and XML that (according to him) came to Kurt Cagle during a sleepless night in the hotel room, it was time for me to drive home. Perhaps next year I’ll be able to stay for the full week, and not miss the XML games that were scheduled.

(note: cross-posted at the ifactory blog)