So companies have N.I.H. syndrome, "Not Invented Here", a reluctance to use pre-existing code from outside group. I certainly suffer from that sometimes, because coding things is fun, and generally my homebrew solutions are compact and focused and you can understand the codepath without having to know how it tries to solve 8 other dudes' problems as well. But sometimes I think my company suffers a bit from N.I.S.E...
Here's an article that kind of supports my view...
Thursday, May 29, 2014
Wednesday, May 28, 2014
display: inline-block;
"inline-block" is one of those CSS bits that tends to sneak under my radar. I should think about it more, because it has properties similar to "float", but without that weird "a container with nothing but float'd objects will collapse leaving no space for the objects".
Anyway, we had a span that we wanted to have a min-width on -- the content of a table td had a dotted underline to indicate it was clickable/editable, but we needed to "hold the area" if the field was empty. (Previously we held it with but we were having weird html escape issues.) Long story shorter, it didn't work until we specified that the span was "display:inline-block".
Anyway, we had a span that we wanted to have a min-width on -- the content of a table td had a dotted underline to indicate it was clickable/editable, but we needed to "hold the area" if the field was empty. (Previously we held it with but we were having weird html escape issues.) Long story shorter, it didn't work until we specified that the span was "display:inline-block".
Tuesday, May 20, 2014
verbs and icons and my dad
My mind seems to be wired in terms of verbs: the roles things play, versus an essentialist notion of "what they are". This is a powerful way of thinking about the things, but it can have some odd side effects. For instance, I am surprisingly slow at recognizing certain icons and associating them with the software functions they go with.
To the right is my OSX Dock at work. Most of the images are relatively associate with their function: Sourcetree looks like a file tree, Stickies looks like post-its, Terminal looks like a terminal window. A few others, like Chrome and and Vidyo (the isomorphic cube) make up for the lack of use-association with great big hunks of color. (Finder I remember because it's always at the top of the list - that's the same kind of positional memory I rely on in iOS. Again, it's not that I can't hunt and find icons, I just don't want to have to for the icons I use the most.)
This little guy has always proven problematic:
It's for the (very good, and free) "Komodo" Editor, and I guess it supposed to be a dragon or lizard head. I don't use it as much as I used to, though.
But lately, my recognition nemesis is this guy:
That's for IntelliJ by JetBrains (hence the J?) the editor I spend most of my coding time in these days. But that icon... though the other day (and I'm chagrined at how long it took me) I realized I could use another hook. Those are the initials of my dad, Jim.
Obviously, there's no particularly strong natural association between my deceased father and a code editor, but in this case the other connections I have are stepping in and making me think of James Israel when I sense myself hunting for the right icon... I actually enjoy the little tribute of it, as weird and idiosyncratic as the connection is.
To the right is my OSX Dock at work. Most of the images are relatively associate with their function: Sourcetree looks like a file tree, Stickies looks like post-its, Terminal looks like a terminal window. A few others, like Chrome and and Vidyo (the isomorphic cube) make up for the lack of use-association with great big hunks of color. (Finder I remember because it's always at the top of the list - that's the same kind of positional memory I rely on in iOS. Again, it's not that I can't hunt and find icons, I just don't want to have to for the icons I use the most.)
This little guy has always proven problematic:
But lately, my recognition nemesis is this guy:
Obviously, there's no particularly strong natural association between my deceased father and a code editor, but in this case the other connections I have are stepping in and making me think of James Israel when I sense myself hunting for the right icon... I actually enjoy the little tribute of it, as weird and idiosyncratic as the connection is.
Thursday, May 15, 2014
angular pitfalls: the need for $scope.$apply()
Long story short: sometimes, especially when you're using widgets "outside the angular ecosystem" and/or you're using ng-if type logic, you might get burnt by the way components inherit $scope; in particular, primitive variable types might get "shadowed", so you would change $scope.someVar, and it doesn't change in the parent scope (where it actually matters for talking with the rest of your page)
One work around is using $scope.$apply() like this article suggests. For me, that was a pretty quick solution, with minimal code changes.
Another idea is avoiding shared pirimitive variables directly on $scope, put it in a map-like object instead. My suggestion for naming that is $scope.scopeNoReallyShareThisScope... but I'm feeling especially cynical about angular.js at the moment. A giant forest of hard-to-monitor scope-based couplings between DOM and code is no way to live.
Monday, May 12, 2014
thinking about angular and verbs and nouns and oo
I admit, angular.js has not come as easily to me as I would have liked.
So it bums me out, because the ability to pick up new technology is important.
On the other hand, some technologies just work better for me* and besides it's not like it's the first platform I was a bit slow to pick up. And on the third hand: some technologies just aren't that great (and some have fallen into the wastebin of history) and maybe I should trust my instincts.
EJB 1.0 sticks out in my mind as one of those.** "Wicket" for doing Web UIs in Java was another one.***
But Angular has a lot of industry momentum, and a few of my friends REALLY dig it. More importantly, my company seems dedicated to it right now, so I need to dig in. So my excuse for this rant is maybe by isolating the differences between Angular and how Kirk Thinks Things Should Be Done I can reset to a beginner's mind and set aside those blocking assumptions.****
In general, coding seems to divide into two camps: programming via verbs, and programming via nouns. The first camp is good old "imperative programming"... tell the computer step by step what to do. The end goal of the second camp is declarative programming: tell the computer what you're trying to do in broader terms, and let it work out the details of how to do it.
(For a while, "Object Oriented Programming" seemed the main path to that promised land. And OO was *so* assumed to be The Way, that when I saw this piece in the early 2000s, it was kind of a revelation: Object Oriented Programming Oversold. That site looks like a Dr. Bronner's Soap level of rant, but I think it has some truth: my strongest take away from that was while OO is good for some things, the assumption that it was the ultimate way of coding the universe sometimes came at the cost of industry focus on other technologies, like relational databases. And also, it's ok to challenge some industry assumptions.)
So some engineers prefer to look and see if someone else has solved their problem already with a reusable solution. I find a problematic synergy often results: there's a good chance that if it solves your problem, it's a solution that solves about a dozen other people's problems as well. And so there's some complex level of configuration to bend it to your will. So you've had to spend time understanding the problem AND a new configuration syntax - and God Help You if the thing still can't do QUITE what the requirements describe, because now you have to dive into a giant heap of someone else's code that's solving your problem as well as those twelve other folks.
And then when things go wrong: if you've done this programming of "set up your nouns" and then things go wrong, your stack trace is going to be a hopeless mess of someone else's code, abstracted out to high heaven, with the actual controlling bits tucked away in some memory structure, somewhere. A stacktrace - that critical tool for most debugging - is a pile of verbs: do this, do this, do this, and when that "this" is a verb related to your task at hand, you're in much better shape.
You can get around this, though, when the widgets you adhere to a Unix philosophy of "do one task, do it well" for your widgets, but keep the main program flow to yourself. Outsource those difficult bits, but always keep a firm grip on the main control flow, is my advice.
But of course, that's where Angular disagrees. Angular wants to be your UI's world and own your stacktraces at all times. It will invent new and arcane syntaxes at the drop of a hat. Sometimes I worry people who come to Angular without doing a lot of browser based UI work might not realize how easy some of the things Angular promises to make easy already are. (For a nice rant along these lines, check out Code of Rob's You Have Ruined Javascript that was making the rounds a few weeks ago.)
So that's one of my beef with Angular. The other one I have is this: it really tightly couples the DOM and the Javascript. It views the two, amalgamated, as the conceptual "View" of MVC. It's your nouns (visible in the DOM; less visible with scope variables) and your verbs all together in one big stew. I finally realized that my conception is that the DOM is rightly more static than that; the DOM should be more decoupled from the Javascript, with information only flowing two and from the underlying code in easy-to-track, specific points, not all over the place with a heap of watched variables and HTML snippets that kind of sort of know how to build themselves from that shared scope memory.
When I was working with jQuery and the DOM directly (using templating as a "do one thing, do it well" add-on, not the fundamental engine of control), it was very natural to put in animations and to do good user input cleaning, because everything happened as transitions: verbs that update nouns. Angular can do both these things, but IMO it doesn't happen as naturally. It took me a while to get my head around you could have different structures for the server communication and the interaction with the DOM (basically DTOs) because I think Angular likes to pretend it's this world where there's just nouns making the UI in the front, talking with the server in the back.
Alright, enough rambling. I need to clear my thoughts and return to a beginner's mind and try to see thing like an Angular person would... but it ain't gonna be easy. (Angular has a notorious learning curve and man am I feeling it) Sometimes it's weird: every time I witness someone tracing through some Angular, it strikes me as being more difficult for them than tracing through more normal code would have been. Yet somehow, once all the dues have been paid and the kool-aid drunk, all these negatives add up to a positive of a more sustainable and flexible code base.
* I can't even tell you how empowering my deep dive into CSS and JQuery in 2010 was.
** I knew I was in trouble when the book I was reading said something like "the EJB development team will generally consist of 5 people"... they tell me later versions got a little better.
*** Wicket assumed Java engineers were just PETRIFIED of learning even the most basic javascript, but were fine with html, so you'd have to make these carefully parallel nested Java/nested div HTML structures, and god help you if you wanted to make your own widget, you'd have to become master of this byzantine 7-step request/response lifecycle process.
**** Did I mention I have nigh-superhuman abilities to rationalize my personal preferences? But again, it's hard for me to isolate my biases and protective beliefs from the hard-won intuition born of two decades of programming.
So it bums me out, because the ability to pick up new technology is important.
On the other hand, some technologies just work better for me* and besides it's not like it's the first platform I was a bit slow to pick up. And on the third hand: some technologies just aren't that great (and some have fallen into the wastebin of history) and maybe I should trust my instincts.
EJB 1.0 sticks out in my mind as one of those.** "Wicket" for doing Web UIs in Java was another one.***
But Angular has a lot of industry momentum, and a few of my friends REALLY dig it. More importantly, my company seems dedicated to it right now, so I need to dig in. So my excuse for this rant is maybe by isolating the differences between Angular and how Kirk Thinks Things Should Be Done I can reset to a beginner's mind and set aside those blocking assumptions.****
In general, coding seems to divide into two camps: programming via verbs, and programming via nouns. The first camp is good old "imperative programming"... tell the computer step by step what to do. The end goal of the second camp is declarative programming: tell the computer what you're trying to do in broader terms, and let it work out the details of how to do it.
(For a while, "Object Oriented Programming" seemed the main path to that promised land. And OO was *so* assumed to be The Way, that when I saw this piece in the early 2000s, it was kind of a revelation: Object Oriented Programming Oversold. That site looks like a Dr. Bronner's Soap level of rant, but I think it has some truth: my strongest take away from that was while OO is good for some things, the assumption that it was the ultimate way of coding the universe sometimes came at the cost of industry focus on other technologies, like relational databases. And also, it's ok to challenge some industry assumptions.)
So some engineers prefer to look and see if someone else has solved their problem already with a reusable solution. I find a problematic synergy often results: there's a good chance that if it solves your problem, it's a solution that solves about a dozen other people's problems as well. And so there's some complex level of configuration to bend it to your will. So you've had to spend time understanding the problem AND a new configuration syntax - and God Help You if the thing still can't do QUITE what the requirements describe, because now you have to dive into a giant heap of someone else's code that's solving your problem as well as those twelve other folks.
And then when things go wrong: if you've done this programming of "set up your nouns" and then things go wrong, your stack trace is going to be a hopeless mess of someone else's code, abstracted out to high heaven, with the actual controlling bits tucked away in some memory structure, somewhere. A stacktrace - that critical tool for most debugging - is a pile of verbs: do this, do this, do this, and when that "this" is a verb related to your task at hand, you're in much better shape.
You can get around this, though, when the widgets you adhere to a Unix philosophy of "do one task, do it well" for your widgets, but keep the main program flow to yourself. Outsource those difficult bits, but always keep a firm grip on the main control flow, is my advice.
But of course, that's where Angular disagrees. Angular wants to be your UI's world and own your stacktraces at all times. It will invent new and arcane syntaxes at the drop of a hat. Sometimes I worry people who come to Angular without doing a lot of browser based UI work might not realize how easy some of the things Angular promises to make easy already are. (For a nice rant along these lines, check out Code of Rob's You Have Ruined Javascript that was making the rounds a few weeks ago.)
So that's one of my beef with Angular. The other one I have is this: it really tightly couples the DOM and the Javascript. It views the two, amalgamated, as the conceptual "View" of MVC. It's your nouns (visible in the DOM; less visible with scope variables) and your verbs all together in one big stew. I finally realized that my conception is that the DOM is rightly more static than that; the DOM should be more decoupled from the Javascript, with information only flowing two and from the underlying code in easy-to-track, specific points, not all over the place with a heap of watched variables and HTML snippets that kind of sort of know how to build themselves from that shared scope memory.
When I was working with jQuery and the DOM directly (using templating as a "do one thing, do it well" add-on, not the fundamental engine of control), it was very natural to put in animations and to do good user input cleaning, because everything happened as transitions: verbs that update nouns. Angular can do both these things, but IMO it doesn't happen as naturally. It took me a while to get my head around you could have different structures for the server communication and the interaction with the DOM (basically DTOs) because I think Angular likes to pretend it's this world where there's just nouns making the UI in the front, talking with the server in the back.
Alright, enough rambling. I need to clear my thoughts and return to a beginner's mind and try to see thing like an Angular person would... but it ain't gonna be easy. (Angular has a notorious learning curve and man am I feeling it) Sometimes it's weird: every time I witness someone tracing through some Angular, it strikes me as being more difficult for them than tracing through more normal code would have been. Yet somehow, once all the dues have been paid and the kool-aid drunk, all these negatives add up to a positive of a more sustainable and flexible code base.
* I can't even tell you how empowering my deep dive into CSS and JQuery in 2010 was.
** I knew I was in trouble when the book I was reading said something like "the EJB development team will generally consist of 5 people"... they tell me later versions got a little better.
*** Wicket assumed Java engineers were just PETRIFIED of learning even the most basic javascript, but were fine with html, so you'd have to make these carefully parallel nested Java/nested div HTML structures, and god help you if you wanted to make your own widget, you'd have to become master of this byzantine 7-step request/response lifecycle process.
**** Did I mention I have nigh-superhuman abilities to rationalize my personal preferences? But again, it's hard for me to isolate my biases and protective beliefs from the hard-won intuition born of two decades of programming.
Friday, May 9, 2014
ya learn something old every day: select tag with optgroup
So even though it may have been sort of around since 2000 somehow I missed the optgroup tag, it just flew under my radar. It lets you add grouping/headers in side the humble select tag.
So with code like
<select>
<optgroup label="first group">
<option>option 1</option>
<option>option 2</option>
</optgroup>
<optgroup label="second group">
<option>option 3</option>
<option>option 4</option>
</optgroup>
</select>
you get something like this:
In theory you should be using labels for the option (for backwards compatibility) with the content of the option tag being the version displayed for non-optgroup labels...
I learned about this kind of the hardway... there's a reasonable cool jquery enhanced select box widget called select2. Its example page is a bit crap... the first example source doesn't mention anything about optgroup, but the exampl on the left is using it as part of a "normal select box".
So with code like
<select>
<optgroup label="first group">
<option>option 1</option>
<option>option 2</option>
</optgroup>
<optgroup label="second group">
<option>option 3</option>
<option>option 4</option>
</optgroup>
</select>
you get something like this:
In theory you should be using labels for the option (for backwards compatibility) with the content of the option tag being the version displayed for non-optgroup labels...
I learned about this kind of the hardway... there's a reasonable cool jquery enhanced select box widget called select2. Its example page is a bit crap... the first example source doesn't mention anything about optgroup, but the exampl on the left is using it as part of a "normal select box".
Tuesday, May 6, 2014
lessons learning
So my company decided to keep on using datatables, since we already had time invested, and there is a pretty good community for it, etc.
Suddenly, though, our code broke. And we weren't sure why.
I did a lot of javascript debugging. At first it was weird because we were using a property named "length" for a very specific purpose. It was for the function we made for https://datatables.net/reference/option/ajax#function but that page doesn't describe what's in "data", so it took me a while to trust that "length" was the property we really wanted, especially when its current value was showing up as null or even NaN.
(Another lesson learned: Any given "NaN" Not-A-Number value is NOT the same as any other "NaN" value (this is so you don't think 5/0 == 3/0, or something) so about the only way to test for something being NaN is a specialty isNaN() function.) And NaN != undefined, unfortunately.)
Anyway, later in my search I found http://datatables.net/manual/server-side that seemed to confirm, as dumb a property name choice as it is, "length" was what we were looking for.
So, using chrome debugger, I found that that value ultimately derives from _iDisplayLength in jquery.dataTables.js -- I spent too many hours trying to set up breakpoints wherever it might be set, but couldn't find anything... as soon as I saw it, it was already NaN! Frustrating.
At this point, empirically, we realized that our Bower instance had upgraded the "scroller" plug in from 1.2.0 to 1.2.1, and that putting it back would fix the problem.
So I had no idea! Part of the thing is I was looking in /scripts/js/jquery.dataTables.js, while this script that was changing the variables I was desperately hunting for was in /js/lib/bower/datatables-scroller/js/dataTables.scroller.js -- exacerbating it, any variable starting with an underscore is usually considered rather private, but by convention. Not the case with Datatables plugins though, which I knew but kind of forgot. So I forgot to search across .js files, either in my IntelliJ editor, or in chrome (chrome isn't great at doing cross-js file searches though -- see http://stackoverflow.com/questions/4145266/how-to-search-all-loaded-scripts-in-chrome-developer-tools for some info on that)
Not helping things was the snarky response I got from the datatable forums... maybe my own dumb fault for not following the "you must have a test case!" rules they apparently have, but man-- making a simple test case from our pile of angular and Server-side AJAX seemed pretty unlikely. So https://datatables.net/forums/discussion/20839/contents-of-ajax-function-data-param-determining-how-many-records-to-load is another view of that.
Too much complexity, I think, in both the build tools we're using, and the plugins. But we learned some good lessons about locking down version numbers.
Suddenly, though, our code broke. And we weren't sure why.
I did a lot of javascript debugging. At first it was weird because we were using a property named "length" for a very specific purpose. It was for the function we made for https://datatables.net/reference/option/ajax#function but that page doesn't describe what's in "data", so it took me a while to trust that "length" was the property we really wanted, especially when its current value was showing up as null or even NaN.
(Another lesson learned: Any given "NaN" Not-A-Number value is NOT the same as any other "NaN" value (this is so you don't think 5/0 == 3/0, or something) so about the only way to test for something being NaN is a specialty isNaN() function.) And NaN != undefined, unfortunately.)
Anyway, later in my search I found http://datatables.net/manual/server-side that seemed to confirm, as dumb a property name choice as it is, "length" was what we were looking for.
So, using chrome debugger, I found that that value ultimately derives from _iDisplayLength in jquery.dataTables.js -- I spent too many hours trying to set up breakpoints wherever it might be set, but couldn't find anything... as soon as I saw it, it was already NaN! Frustrating.
At this point, empirically, we realized that our Bower instance had upgraded the "scroller" plug in from 1.2.0 to 1.2.1, and that putting it back would fix the problem.
So I had no idea! Part of the thing is I was looking in /scripts/js/jquery.dataTables.js, while this script that was changing the variables I was desperately hunting for was in /js/lib/bower/datatables-scroller/js/dataTables.scroller.js -- exacerbating it, any variable starting with an underscore is usually considered rather private, but by convention. Not the case with Datatables plugins though, which I knew but kind of forgot. So I forgot to search across .js files, either in my IntelliJ editor, or in chrome (chrome isn't great at doing cross-js file searches though -- see http://stackoverflow.com/questions/4145266/how-to-search-all-loaded-scripts-in-chrome-developer-tools for some info on that)
Not helping things was the snarky response I got from the datatable forums... maybe my own dumb fault for not following the "you must have a test case!" rules they apparently have, but man-- making a simple test case from our pile of angular and Server-side AJAX seemed pretty unlikely. So https://datatables.net/forums/discussion/20839/contents-of-ajax-function-data-param-determining-how-many-records-to-load is another view of that.
Too much complexity, I think, in both the build tools we're using, and the plugins. But we learned some good lessons about locking down version numbers.
Thursday, May 1, 2014
titles and lenses and handles, oh my!
Three notes from my job.
1. the "title" attribute.
It took a side comment from a (stridently non-UI) coworker to remember that the simplest way to get an informational popup (like the old "img alt" text) for an existing page element is to use the "title" attribute. I kind of forgot about that one! My thinking was stuck back where you only had the "alt" tag, and it was just for images, but now almost all DOM elements support bearing a "title". I was all ready to make up some kind of jQuery onhover thing, but HTML5 had me covered.
2. fisheye lens for group remote scrums over laptop video
I can recommend this set of lenses for use with a Macbook if you want to let the party on the other side get a wider view. Specifically, the fisheye lens -- the "wide angle" is just a weaker version of that, and the macro/closeup is kind of useless - at least on my iPhone, it ruins the devices' ability to focus. But with 3 or 4 of us on one couch for "video scrum" (wait, shouldn't that be a standup?) the springy clip lens works well.
3. door handles and clever hints
One of my favorite books is Donald Norman's The Design of Everyday Things. One of its famous takeaways is the design of doorhandles, how they hint at which way the door will be moving. It points out that a horizontal bar generally implies pushing, and a vertical bar is generally meant to be grabbed and pulled (and both of these have to do with the physiology of the arm and hand.) At my job, however, both sides of the door use vertical bars:
And yet, I never try to use the handle the wrong way. What's going on? I took a closer look, and there's a subtle but important physical difference: the "push" handle is mounted at around a 45-degree angle, and the "pull" handle is closer to flush with the door. That difference is enough to strongly suggest the right behavior!
I was impressed by the cleverness and effectiveness of the design. Though I pointed it out to my coworker, and she says she always relies on what the sign above says. (And in the one case where the sign is missing, and the sign from the other side of the semi-transparent door shines through (albeit reversed text) she finds it very confusing.) So that was another valuable lesson for me: different people read different sets of clues.
Finally, an aside about "The Design of Everyday Things"... this is a book that has disdain for objects that sacrifice usability for aesthetic appearance, and also for the professional groups that reward that emphasis-- "probably won an award" it sniffs disdainfully, at doors and other devices that go for sleek minimalism over hints at use. Ironically it didn't heed its own advice, at first! Its original title was "The Psychology of Everyday Things": a pleasing title with a lovely acronym "POET" (repeatedly used in the book). And indeed, the book won awards! Unfortunately the title confused booksellers who didn't know whether to file under psychology, or design, or what. So a less clever, more understandable title was adopted. Still a fine read, however.
1. the "title" attribute.
It took a side comment from a (stridently non-UI) coworker to remember that the simplest way to get an informational popup (like the old "img alt" text) for an existing page element is to use the "title" attribute. I kind of forgot about that one! My thinking was stuck back where you only had the "alt" tag, and it was just for images, but now almost all DOM elements support bearing a "title". I was all ready to make up some kind of jQuery onhover thing, but HTML5 had me covered.
2. fisheye lens for group remote scrums over laptop video
I can recommend this set of lenses for use with a Macbook if you want to let the party on the other side get a wider view. Specifically, the fisheye lens -- the "wide angle" is just a weaker version of that, and the macro/closeup is kind of useless - at least on my iPhone, it ruins the devices' ability to focus. But with 3 or 4 of us on one couch for "video scrum" (wait, shouldn't that be a standup?) the springy clip lens works well.
3. door handles and clever hints
One of my favorite books is Donald Norman's The Design of Everyday Things. One of its famous takeaways is the design of doorhandles, how they hint at which way the door will be moving. It points out that a horizontal bar generally implies pushing, and a vertical bar is generally meant to be grabbed and pulled (and both of these have to do with the physiology of the arm and hand.) At my job, however, both sides of the door use vertical bars:
And yet, I never try to use the handle the wrong way. What's going on? I took a closer look, and there's a subtle but important physical difference: the "push" handle is mounted at around a 45-degree angle, and the "pull" handle is closer to flush with the door. That difference is enough to strongly suggest the right behavior!
I was impressed by the cleverness and effectiveness of the design. Though I pointed it out to my coworker, and she says she always relies on what the sign above says. (And in the one case where the sign is missing, and the sign from the other side of the semi-transparent door shines through (albeit reversed text) she finds it very confusing.) So that was another valuable lesson for me: different people read different sets of clues.
Finally, an aside about "The Design of Everyday Things"... this is a book that has disdain for objects that sacrifice usability for aesthetic appearance, and also for the professional groups that reward that emphasis-- "probably won an award" it sniffs disdainfully, at doors and other devices that go for sleek minimalism over hints at use. Ironically it didn't heed its own advice, at first! Its original title was "The Psychology of Everyday Things": a pleasing title with a lovely acronym "POET" (repeatedly used in the book). And indeed, the book won awards! Unfortunately the title confused booksellers who didn't know whether to file under psychology, or design, or what. So a less clever, more understandable title was adopted. Still a fine read, however.
Subscribe to:
Posts (Atom)