The Gaff

February 23rd, 2008

I’m writing this from the main dining hall of The Gaff, the #1 cyber pub in Port Aransas, TX. A well-known local just walked in to a shout of acclaim. The owner then told us about the Thursday pirate raid pub crawls they do from here.

I don’t have much to say - or, actually, I could probably stay in this place and write a few bad novels over the course of a season. I did however feel compelled to blog from here.

The pizzas just came, as did Allie’s pirate-sized meatball sandwich, so I sort-of have to wrap this up.

Later…

The Gaff is everything you could want from a run-down beach hangout. The menu has like four things on it. The weirdly efficient bartendress puts the pizzas together and they were approx. of BB’s quality. Pyramid Wheat on tap. Belt sanders used in periodic belt sander races decorate the grimy windows. There’s an enormous bigscreen tv that doesn’t seem to work properly. They have free wireless, and this paean is good evidence of what a fine idea that is.

We walked in, and for some reason the kids immediately started exploring all 1000 square feet of the place, with many declamations of “Classic!” as the piratical denizens paused (briefly) from their beer-cigarette cocktails.

After sitting down, Pat loudly announced, “This is just like Las Vegas!”

Lilies

February 16th, 2008

I planned something maudlin. This rainy day swept into my head on a sharp cold wind, and there roiled bleak clouds of pathos. I wanted to write about the ephemera of memory, of tattered recollections I’d pay dearly to restore, of Friday parties, of lazy trips to Grapevine, laughing drives along the Secret Back Way, cuddling up with boxes of beer. I wanted to capture a thousand memories of a thousand moments, a thousand smiles.

I decided that was all dust, blown away. I won’t fail to take that sort of thing seriously when it’s happening any more. I’m a coward who hides behind a cheap cynical mask. I’m not an interesting coward so that’s not worth writing about. I stifle my desire to appreciate and wonder because I’m afraid about what happens when it ends, but I’m the only victim of that.

So, no more blah blah blah.

O Freunde, nicht diese Töne!
Sondern laßt uns angenehmere
anstimmen, und freudenvollere!

From somewhere came into our house a potted Lily of the Valley, Convallaria majalis. (There are various sad legends associated with the flower, but I don’t want to get into that now.) It started blooming a few days ago, so I carried it up to the improvised studio and took a bunch of pictures.



The leaves and flowers contain all sorts of scary-sounding chemicals that have something to do with heart attacks. I’m not sure if that means you should keep the plant around so that you can stuff a handfull of it into the mouth of a quivering patient on the floor. Somehow, even if it’d be effective, I can’t imagine how you’d explain it all to the paramedics.



With the lights all set up I got some good pictures of the kids too, but I’ll save those.

Swimming the foreverness of a slow morning

February 14th, 2008

One of the things that has contributed to the crack-up I’ve experienced (publically, now, and I’ll let you know eventually whether I recommend that) is a lack of patience. Conditioned by years sitting as I am now at the helm of an Internet-wired computer, I’ve gotten used to leaping instantly from wanting-to-know to knowing. The future, however, doesn’t send much e-mail.

It’s been hard to write this. I’ve been thinking a lot about being nuts, but for the past few days I’ve been feeling so not-nuts that the topic seems pointless and uninteresting. I keep testing myself with the various stimuli that for months fueled the darkness and confusion in my head, and while I still get twinges sometimes, they’re not making me stupid.

It’s definitely the case that I’ll never dismiss claims by my female friends that body chemistry is affecting their behavior. The only chemicals I have to worry about are whisky and cheese, and I don’t think they had much to do with most of my issues (though behavior-wise the drink hasn’t done me any favors). I’m such an emotional wimp that I can be driven into a bad state by a little world-is-changing stress, so I imagine that scary hormones would make me a complete wreck.

So this inability to know what’s going to happen - the natural state of existance, of course - gets on my nerves. Other stuff does too, and I know now that I’m really a giant baby. I don”t know how to improve that situation. I’m getting used to it, maybe.

Anyway today I went to a concert, sort-of. I think really you’d have to call it more of a church service fragment. I don’t know what you call those. I don’t consider myself a religious person, or a spiritual person, but I do consider myself a person. Being a person is strange and hard and amazing. For a while I was doing a really bad job.

Then, during this concert, a segment of poetry reading included the lines

I can only agree to open arms
of acceptance to imperfect friends,
explain as cogently as I can
that they are most certainly
alright as they are.

As the beneficiary of such commitments over the past few weeks, I found it suddenly very hard to keep my composure. I’m one imperfect friend, let me tell you. Sometimes I don’t even know why I feel I can think of myself as a “friend” to my friends. They’re such nice people, and I’m humbled by their support for me. Years ago, my home was often a focal point of activity among a circle of friends. I like cooking, and I cooked for friends who couldn’t or wouldn’t. Sometimes we’d just do nothing. For whatever reason this happened a lot less after we moved to Austin: I was working harder, maybe, or just getting older.

Having children of course changed things. It’s pretty easy to focus inwards, particularly in my case, gaining a complete clan in one step. The feeling of distance from people is something I got used to without even noticing it. I’m tired, my wife is tired (and her ears ring from every long day with three kids around), and it’s just so easy to be insular. What has that cost me?

Am I Depressed?

February 5th, 2008

That title isn’t really a question; it’s a joke. See there’s this guy, or there was this guy maybe, named Dan Ashwander, who was pretty, well, nuts, and he wrote this book called, Am I Insane? So I made the title of this blog post, “Am I Depressed?”. Funny.

Actually it is kind-of a question. I don’t know what it means to be “depressed.” other than the colloquial “gee I’m depressed because my sandwich got wet.” I’m sure that real depressed people who are unfortunate enough to land here probably think I’m a total poser. My apologies, really. My apologies also to anybody who’s wondering why, like the rest of the American population, I don’t go see a doctor who’ll tell me whether I’m depressed or not and send me on my way with a sack of pills appropriate to either answer. That’s not the kind of thing I ever imagined myself doing back when I wasn’t wondering whether I’m depressed, and I still have this quaint, feeble idea that clinging to that conviction gives me some connection to my ordinary sane self.

The chronic feeling that there’s a hedgehog inside my chest is so familiar now that I’m startled every now and then when it temporarily abates. When that feeling is strong I literally cannot eat, so of course the consequent lack of bodily nutrients only makes everything worse. My powers of rationalization and self-policing are all haywire, and I have periodically realized that the “good sense” I’ve been repeating to myself is completely wrong. That makes the hedgehog happy, of course, but it’s really starting to piss me off. Now I’m typing this, and I know that what I’m doing is burdening various nice people with having to think about me and this stupid rodent.

I have this sophomoric concept of the “meaning of everything.” I figure that the universe is just here, and there’s no rhyme or reason to it. Yet here I am, thinking, “Here I am,” and thinking about thinking, “Here I am.” Thus maybe those things go together: the universe is here to be thought about by creatures sitting there thinking, “Here I am.”

I asked Pat one day, “Pat if a big tree fell down in a forest, and there were no people or creatures near enough to hear it, would it make any noise?”

“Probably not,” was his immediate answer. That, I felt, strongly supported my theory. The universe needs me to think about it. It struck me back a while ago, while listening to a lecture about dromaeosaur taxonomy, that during the Mesozoic the Earth was covered with millions and millions of creatures running around gnawing on plants and eating each other, and yet none of them, nobody anywhere, was thinking about that reality, or thinking, “Here I am.” How did the world manage to exist? Day after day, year after year, like a model train setup in a store window, just existing without awareness. Well, I “reasoned,” maybe it works for there to be creatures somewhere, anywhere, thinking, “Here I am,” and thinking about thinking, “Here I am.” Maybe that makes things work out for the universe as a whole. Indeed, maybe me thinking now about the poor lonely Mesozoic is what made the Mesozoic exist.

Therefore, we have this obligation (so my infantile philosophy goes) to keep things rolling by thinking, “Here I am,” and by thinking about thinking, “Here I am.” It’s consequently important to be supportive and charitable to all those other people who need to be thinking, “Here I am” - my kids, wife, friends, and ultimately everybody. I now find myself in this situation where I’ve dropped the ball and kicked it into the neighbor’s yard. I’m leaning on kind normal people, hell virtually slobbering on them, stepping on their feet as I emotionally stagger around, and I have no business being such a mess. It’s totally unreasonable and horribly embarrassing. I know objectively that I’m not a super-being, impervious to mental maladies, but honestly it’s humiliating. Of course, feeling humiliated and weak doesn’t help my overall outlook.

OK so I don’t know where I’m going with this. The rodent is still there. I’m getting better at keeping a grip on things, and filtering out wildly inappropriate self-advice, but it takes a lot of energy and I can’t keep it up all day. I’ve never responded to stress this badly. I think the best I can do for now is sincerely apologize to the people who seem so inexplicably willing to put up with me. This really has got to stop, so please believe me when I say that I’m putting everything I can into snapping out of this funk, and I vow to make it up to everybody somehow eventually.

I should note in closing, as I proofread, that it’s extremely important to me that nobody take this too seriously. My innate fear of pain is a giant bulwark of strength, regardless of anything else going on in my head, so it’s absolutely not the case that I’m in danger of damaging myself. I’ll get better.

Crappy Job Ads on craigslist

January 18th, 2008

Opinions on how we should and shouldn’t compose our resumes are a dime a dozen in the blogosphere. Well, in fact they’re free, though some may be worth a little more. The topic is an old one, and though the Internet and modern practices (like using craigslist or monster) may have brought new rules into play, it’s still about making yourself look smart, experienced, and sane.

The flip side of resume writing is the art of advertising open positions when seeking to hire people. I can’t keep track of whether we’re in a “buyer” or “seller” market in the software development world, but it’s clearly true that individual companies in individual markets frequently find themselves fairly desperate to hire developers. My own experience is that it takes quite a while to find candidates, and even longer to hit upon a good one.

Thus it seems to me that writing good copy for craigslist “help wanted” adds would be something employers do as a matter of course. Sadly, that’s not the case. They’re generally:

  • ugly;
  • rife with spelling and grammar errors;
  • composed of weird or stilted language;
  • jammed with buzzwords and product/technology names.

I know that some of the problems stem from the route the ads take from the hiring manager through the HR group (and possibly through the recruiters), but that’s hardly an excuse. The end result is that I read the ads, you read the ads, and we form opinions about the personality and culture of the organization. I caught myself the other day rolling through craigslist ads, one after the other, shaking my head after almost every single one. Ad after ad leaves me with impressions of people in cheap suits, dingy offices, and wildly disorganized (or just crazy) product development environments. You know what I’m talking about: little businesses where the guy in charge tells you that lots of the work was done by “the smartest guy I know, he’s a wiz”. Dreary failure is the vague mental picture I form.

What’s going on? Is it really the case that most businesses trolling craigslist are seedy or dysfunctional? I know that the ads are dirt cheap (free here), but the page view rate is so high that even businesses with money to blow on recruiters would be foolish not to use the service when they’re in need. (The place I work now has used craigslist with no success; I never looked at our ads.)

Indulge my laughable fantasy that somebody in a position to be influenced by my advice might read these words: take care with your craigslist ads. Think about them carefully, about the tone, the language, and the image they create. Correct the misspellings and grammar errors. Clean up the random capitalization of Important Words, and NOTHING SHOULD BE ALL-CAPS. Get somebody who actually knows what the buzzwords mean to review the way you’ve piled them on top of each other, and think about whether the things you insist are essential skills are really essential. (Did your top developers on your key products have all those skills back a year or two ago?)

Steve Yegge wrote about “weasel words” in resumes. In my opinion there’s a parallel species of words that crop up in job ads. I’m talking about stuff like “dynamic work environment”. What does that mean? “Should be an excellent team player.” Again, what does that mean? Who do they expect to screen out with that? I don’t want to hear about your corporate “energy”; it’s vaguely creepy and I’ll get the real story (or close to it) in an interview anyway. Just be clear and friendly, and describe the work.

HTML Escaping in Javascript

December 29th, 2007

The Protoype library augments the native “String” class with an “escapeHTML” method. It’s handy for scrubbing user-supplied text onto the page:

  $('someSpan').update(randomString.escapeHTML()); 

I found recently that all that’s “escaped” by the function are the characters ‘&’, ‘<’, and ‘>’. I found that out the hard way when I had assumed it’d also escape single- and double-quote characters. (Why did I assume that? I’m dumb maybe, but I figure it’s nice for building HTML attribute values. Whatever.)

The implementation of “escapeHTML” (on Firefox, at least, and maybe Opera) is pretty odd, and clearly something done for performance. What the library does is to create a div element with a text node in it, and keep that around. A call to the “escapeHTML” function is handled by setting the “data” attribute of the text node to the string being escaped. The return value is then the “innerHTML” property of the div. Thus the function leverages the internals of “innerHTML” and has the translation done in the (presumably) fast compiled innards of the browser. Here’s a rendition of what it looks like; it’s not exactly like this but this is (I think) equivalent:


  escapeHTML: (function() {
    var rv = function(s) {
      var self = arguments.callee;
      self.text.data = s;
      return self.div.innerHTML;
    };
    rv.div = document.createElement('div');
    rv.text = document.createTextNode('');
    rv.div.appendChild(rv.text);
    return rv;
  })()

The simple-minded version used for WebKit and IE looks like this:


  escapeHTML: function(s) {
    return s
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;');
  }

Whether or not I’m right in thinking that the library’s “escapeHTML” function should deal with quotes, I need something that does. Clearly I can’t leverage the “innerHTML” trick, because the browser apparently disagrees with me about quotes. I could clearly just use an extended version of the repeated-”replace” version. There’s another way, however:


  escapeHTML: (function() {
     var MAP = {
       '&': '&amp;',
       '<': '&lt;',
       '>': '&gt;',
       '"': '&#34;',
       "'": '&#39;'
     };
      var repl = function(c) { return MAP[c]; };
      return function(s) {
        return s.replace(/[&<>'"]/g, repl);
      };
  })()

The “replace” function (native to Javascript “String” objects) can take a function as its second argument. The function is passed the results of each match. Thus this version above matches on any of the characters I want to escape, and then translates them to the HTML entities via a little map object. It seems like this would be better in the case of “clean” strings, because the pattern would match nothing and so the string would be returned unchanged.

In order to see what the performance realities were, I started hacking up a little test page. After a while, I got tired of editing and re-editing to see how different tinkerings with the different function versions would affect the timing. What I wanted was a setup to make a little table: different test datasets (short strings, long strings, clean strings, dirty strings) across the top, and the different “escapeHTML” versions at the left. The cells would be the average time of a pass over each string in each test list. Because I’m silly I wanted the table to be filled in as the tests ran, so the numbers would show up while I stared at the screen.

To do the little incremental animation thing made my head hurt for a while. I took a break to cook some muffins (orange cranberry - here’s a tip: when making orange muffins or any sort of orange quick bread, use frozen concentrated orange juice instead of plain juice, and a teeny bit of orange oil) and while I was filling up the muffin cups I had an idea. I think it’s something that people who’ve been using functional languages would probably think of as being perfectly obvious.

Prototype has an “inject” routine, which is like “foldl” in … well, in something; Scheme maybe? I know that in the Erlang “lists” module it’s “lists:foldl”. The function is a method available on any Enumerable object, like an array. It takes two arguments (well, three, but ignore that for now), the first being an initial value and the second being an iterator function. The “inject” mechanism passes the initial value and the first element of the collection to the function. The function does something, and returns a value. That’s passed on in the next iteration, with the second element of the list, and so on. The final return value of “inject” is whatever the last invocation of the iterator returns.

Common pedagogical examples of “inject” do stuff like compute an arithmetic reduction over a list of numbers, or build up an array from a function that interprets values in the source array. In my case, what I wanted was a function, one that I could call to start the sequence of test runs. In other words, I needed to have something that would iterate accross the cells of my table, running the “escapeHTML” versions on each list of test strings.

My muffin epiphany was that I could use nested “inject” loops backwards through the table to build up a function that would run the test for its cell, and then invoke the function from the previous cell. (That’s why I’d go backwards through the array - the last function to run would have to be the first function I built.) Thus the “inject” process would build up a chain of functions wrapped around eachother like Russian nesting dolls.

That ended up as a somewhat general-purpose facility that will take a list of functions (with names) and a list of test datasets (with names), and create a table in a selected container, and then fill in the table test by test:


function timings(container, datasets, functions, repeats) {
  // first make the empty table, with headings and left-side labels
  $(container).update(
    "<table><tr><th></th>#{headings}</tr>#{rows}</table>".interpolate({
      headings: datasets.collect(function(sl) {
        return "<th>#{name}</th>".interpolate(sl);
      }).join(''),
      rows: functions.collect(function(fp, rowNum) {
        return "<tr><td>#{name}</td>#{timings}</tr>".interpolate({
          name: fp.name,
          timings: datasets.collect(function(x, colNum) {
            return "<td id='#{r}_#{c}'></td>".interpolate({r: rowNum, c: colNum});
           }).join('')
        });
      }).join('')
    })
  );
  // now make the nested series of functions, and call the one that pops
  // out the top
  functions.reverse(false).inject(null, function(ff, fl, rowNum) {
    return datasets.reverse(false).inject(ff, function(ff, sl, colNum) {
      var tdid = "#{r}_#{c}".interpolate({
        r: functions.length - rowNum - 1,
        c: datasets.length - colNum - 1
      });
      return function() {
        $(tdid).addClassName('pending');
        setTimeout(function() {
          // average the time for some runs over this test dataset
          var avgTime = $R(1, (repeats || 10)).inject(0, function(avg, n) {
            var start = new Date().getTime();
            sl.list.each(fl.fn);
            return (avg * (n - 1) + (new Date().getTime() - start)) / n;
          });
          $(tdid).update(
            (Math.floor(avgTime * 100) + '').replace(/(dd)$/, '.$1')
          ).removeClassName('pending');
          // call the next function in the chain - this is the one passed
          // in as the first argument by the "inject" mechanism
          ff && ff();
        }, 250);
      };
    });
  })();
}

Note that the per-cell functions operate via timeout. That’s so that the browser has a chance to catch its breath and update the display between test runs. (The 250ms time was just a random guess, but short times like 10ms were too short). You can see the results of my fooling around here. What I found was kind-of interesting.

First, the “weird” way that Prototype does the escaping (via the “innerHTML” trick) is pretty consistent in performance. It’s slower than the “fun” approach (the single regex with a replace function) when strings are clean, I guess because the browser regex code is pretty well optimized, and the pattern is simple. All of the regex routines get slow on larger strings that require scrubbing. The “hybrid” code on that test page is the “innerHTML” trick with a pre-check via regex.

The “Weird 2″ function, which is always slower than “Weird”, is the Prototype “innerHTML” version implemented as in the actual library. Specifically, the div and text node are attached as attributes to the function object itself, and then accessed via “arguments.callee”. In my version (”Weird”), I just used a closure for the elements. Why would the closure be faster?

Oh, and the “multi” ones are the muliple-replace routines.

For my purposes, I’m pretty sure most of the strings that my pages escape are clean. Thus I think I’ll introduce the single-regex version somehow in my world.

Finally, while typing this in, I needed a place to escape the code samples. I think I wrote a C program to do that once a long time ago, but I couldn’t find it. Thus I typed in this page to do it. Maybe people with fancy IDEs have built-in tools for that.

The dark side of {{ }}

December 22nd, 2007

Despite having typed in an enormous amount of Java code over the past seven or eight years, my “discovery” of


return new Foo() {{
  setThingy(whatever);
}};

was embarrassingly recent. Because it lets me work more with values than with statements, I like it a lot, and I try to think in terms of using it.

For those still unaware of this surprisingly old feature of the language, it’s possible in general to add anonymous blocks to class definitions. Everybody knows about


static { foo = new BigFoo(); }

Without the static keyword, the block is treated as an appendage to the constructor code. (I guess they run in declaration order, but I don’t care about that at the moment.) Thus the notation

new T() {{ code; }}

means to construct an anonymous subclass of T with some random code that runs along with the no-args constructor for T. (Of course you can also do that when the constructor does have arguments.)

The dark side of that trick is probably obvious to everybody except me, because the dark side has crept in and wasted a lot of my time recently. The code that you type into that {{ }} block is of course code that’s treated as being in the lexical context of the subclass, not that of your surrounding code. Durr. If the initialization statements refer to method names or variable names that are visible in the base class, then the statements are interpreted as being in those terms. That’s really nice when you’re using this to populate a HashMap


return new HashMap() {{
  for (DungHeap dh : allHeaps()) put(dh.getName(), dh);
}};

However, if the base class you’re subclassing has some protected member variables, watch out! The final variables in the surrounding code you’re referencing as part of the initialization will be shadowed. Same goes for utility methods you’d like to call.

This got me just today with a context variable called “headers”. I was initializing a new MimeMessage instance. Guess what’s a protected member variable of a MimeMessage instance?

I still like that notation, for now at least.

Just what is this Javascript object you handed me?

December 8th, 2007

Modern Javascript “frameworks” like Prototype, jQuery, and Dojo compete to provide flexible, expressive tools, which is a great thing for Javascript developers. It’s truly astounding how effective these relatively simple and concise tools can be.

One of the challenges faced by toolkit designers stems from the malleability of the Javascript environment - the same malleability that makes the tools possible in the first place. In type-happy (I could have written “stodgy”) languages like Java, the question, “what is this thing?” that code behind an API might ask is always easy to answer; in fact as a Java programmer you don’t really ask the question much unless you’ve done things pretty badly. In Javascript, however, there’s never a good answer. Well, there is - the thing is an Object - but it doesn’t do you much good.

So anyway, coding away the other day I came across an interesting bug, one that turns out to be shared by Prototype, jQuery, and Dojo (and maybe others). It was a case of the toolkit code doing something to check to see if a thing passed through an API was of a particular type so that some work could be done with it. In this case, the toolkit code (Prototype) needed to know whether a value was an Array, because if so then something different had to be done than if the value were a simple scalar. Instead of approaching that situation with a pragmatic, dynamic “duck typing” technique, the code took an approach that a Java programmer would recognize.

Specifically the fault was in code that transformed a “Hash” object into an HTTP query string. The client code has a property list of parameter names and values, which is to be used in a GET URL or an XmlHTTPRequest. The Prototype service has to deal with the fact that a single parameter name may be associated with a list of values. (Recall that an HTML form can have more than one input field with the same name.) The Prototype convention here is that the “toQueryString” routine looks for parameters in the Hash object whose values are arrays:


  // this is 1.5.1 code - it's different in 1.6
  // but the problem remains (for now)
  toQueryString: function(obj) {
    var parts = [];
    parts.add = arguments.callee.addPair;

    this.prototype._each.call(obj, function(pair) {
      if (!pair.key) return;
      var value = pair.value;

      if (value && typeof value == 'object') {
        if (value.constructor == Array) value.each(function(value) {
          parts.add(pair.key, value);
        });
        return;
      }
      parts.add(pair.key, value);
    });

    return parts.join('&');
  },
  // ...

(The “addPair” routine that’s hooked up to the return-value array “parts” just builds a “name=value” string with appropriate URL encoding.) See how the code works? There in the loop code where it handles each key/value pair in the Hash object, it checks each value to see if it’s type is “object”. (The Javascript “typeof” is pretty lame.) If it’s an object, then a further test is made to see if the value is an array. That test compares the “constructor” attribute of the value object to the global Array function.

What’s the problem with this? The code is doing something that seems reasonable: if the constructor of the object is the Array function, then it’s an array, right? Sure, this is Javascript, so if the client code has done something stupid like reassign the “constructor” attribute or even reassign the global variable name “Array”, it’ll break, but that would be my fault. Setting that aside, what could possibly go wrong?

First I’ll be philosophical: does that code really need to know for sure that the value was constructed by the Array function? All it really does when it determines that the value is an array is take advantage of the “each” function it expects to find there. I think that a pure (funny word in this case) duck-typing approach would be to check to see if the value object has an attribute called “each” that references a function.

Now on to the practical issue here, the reason that the code is buggy as written. The subtle assumption made in the code is that every array object will have been constructed by the function pointed to by the global variable “Array”. Conversely, it assumes that any object not constructed by the function pointed to by the global variable “Array” must not be a real array. OK then, outside of shenanigans that break things on purpose (reassigning “Array”), how is that assumption problematic?

Well I’ll tell you. A web application can be spread across multiple separate windows. The window objects are linked together into a single DOM graph. Code can “see” up and down the graph into other windows, and functions can be called across window boundaries. In particular, an array can be passed from code on one page into a function on another. The kicker is that every page has its own global context (which means that the term “global” is sort-of questionable), and that includes a “global” variable called “Array.” Oops.

Javascript is not Java. You can’t really put much stock in anything your code might find out about a mysterious parameter, so why compound the problem by asking indirect questions? Just because an object was not apparently constructed by the function you think has to be the one and only “right” one doesn’t mean it won’t work just fine.

This page is a simple example of the problem. Prototype will be fixed soon thanks to the attentions of world-famous Prototype contributor “savetheclocktower.” Dojo and jQuery have similar issues but I haven’t reported them yet. Specifically, jQuery uses the “foo.constructor == Array” deal all over the place. Dojo seems to use “instanceof Array”, which suffers from exactly the same problem. I don’t think that expecting the libraries to work properly on values passed across page boundaries is unreasonable.

Amazon Ring Flash

November 10th, 2007

OK so here’s the home-made ring flash. Ingredients:

  • One small Amazon book box
  • 2 Quantaray slave strobes
  • 2 plastic strap ties
  • 1 rubber band
  • 1 piece of random white-ish cotton cloth
  • Aluminum foil
  • Duct tape

(Credit to Pat for most of the assembly photos.)

Holes are cut in the back of the box, one in the middle for the lens and then two on each side for the strobes:

The strobes fit on the back such that the flashy part kind-of pokes into the holes. Plastic strap things hold them in place:

On the front is some cloth. It’s got a frilly pattern woven into it, but I don’t think that’s important:

The lens pokes through the back, and the box fits more-or-less snugly over the filter:

The lens hood is screwed on (yes, screwed) and a rubber band holds the cloth flaps:

Here you can see the catchlight from the contraption:

That’s all there is to it. I can shoot at 1/160, f10 to f16, depending on how close I am. That gives more depth of field than I’ve gotten with daylight. Gallery from this afternoon, immediately following the (re-)assembly of the ring flash:







(That’s a “Batfaced Cuphea” flower; I didn’t notice the aphids until I saw it on the screen.)

For Melissa, tourmaline with amethyst:

Wulfenite:

Dioptase (I think; might be diopside but the crystals seem too big):

Galena (perhaps with sphalerite but I don’t know):

Big Bugs

November 9th, 2007

Actually just the pictures are big.



These were taken with the Sigma 105 and a home-made “ring flash.” The flash consists of an Amazon book box with the flaps cut off. Through the back (well, the bottom of the box), two holes were cut so that the flash “windows” of two Quantaray cheap-o slave flash units can poke through. The flash units were strap clamped to the box. There’s a round hole in the middle of the box that just fits over the end of the lens (actually it’s over the UV filter). The lens hood holds it in place, sort-of. Then there’s a piece of thin cotton fabric duct-taped over the front (top) of the box, and through a hole in the middle of it pokes the lens hood. Maybe I should take a picture of it.



I don’t know what either of those two things are, exactly. I’ve seen that species of dragonfly a couple of times however, and I have another good picture I got with the Olympus 50mm lens.