So I wandered over the local mall tonight, and found a movie store location closing. Everything's 50% off, right? (60% if you get 4 or more CD/DVD's.) I'm browsing around, and I do a double-take. One of the IMAX films I saw in high school is right in front of me: "Fires of Kuwait".
Bargain aside, this is a terrific find for me. Oh, I could have bought it on Amazon if I really cared, but I barely remembered it. Except for how much I enjoyed watching it. It's a good film.
So I buy it, bring it home and watch it. Inside there are two order forms from "Warner Explorations", where I could order other DVD titles. Some of the titles they offer look interesting. Then I notice the expiration date, in bright yellow. "OFFER EXPIRES 4/1/02"
That tells at least how long ago the DVD was packaged. But if that's an April Fool's joke, it's in pretty poor taste. I bought the DVD four years minus one day after its coupons had expired.
:-)
Our stuff shows up under the "Get To Work" section.
Kudos to glazou for discovering this first.
A few weeks ago, I was wondering about the possibility of debugging C++ and JS at the same time. Venkman's a nice JS-only debugger. I'm using Microsoft's VC++ 2005 Express Edition to debug on the C++ side. (Mind you, I'm really not that great at C++ debugging.) I wondered, on a theoretical basis, how I would debug a problem that happened somewhere in between two JS frames, amid several C++ frames.
As I started pondering potential solutions, it was pretty obvious that I couldn't even get a good stack of the JS and C++ frames at the same time. Components.stack from Venkman returns a nsIStackFrame object. This object has partial info about the JS stack, and none about the C++ frames. For example, I could get the filename and line numbers of stack frames in JS, but I couldn't get the source line. I'm running a debug build of SeaMonkey trunk, and there was no information to be had at all about the C++ code. This is no better than what Error.prototype.stack returns.
Read on for more details, including the reason why a XPCOM debugger is now necessary. Or feel free to blame me for not knowing how to really use a C++ debugger.
I started wondering about this when I discovered a bug to add a JavaScript-based assert() function. Personally, I thought it didn't go far enough. If you're going to assert in chrome, it ought to at least launch a debugger like Venkman. (Of course, my own idea for jslib didn't do that either. :-) )
On the side, there was a discussion on IRC and in-person with timeless and a few others about the possibility of JavaScript calling NS_ASSERTION. Yes, I know, assertions should be fatal and this essentially means JavaScript can demand the program crash. This particular kind of crash should only be requested in extreme conditions, like when Venkman will not give you any useful information to debug a problem from JavaScript.
However, someone (I believe it was timeless) pointed out to me the nsIDebug interface. It took me about five seconds to notice that this interface was actually listed as deprecated...
Up to this point, it was all theoretical. I didn't see a need for getting a full XPCOM stack with both JS and C++ frames in it. I didn't see a need to stop Mozilla in its tracks and force debugging.
Fast-forward to today. I now have an unusual Venkman stack trace staring me in the face:
Error("Traditional JS stack dump")@:0
assertWithStack()@chrome://xulwidgets/content/editorTest/assertWithStack.js:4
onAttrModified([object MutationEvent])@chrome://xulwidgets/content/editorTest/domTreeViewMaker.js:109
nextNode()@:0
noDeepSerialize([object XULElement])@chrome://xulwidgets/content/editorTest/test.js:136
initSource([object Event])@chrome://xulwidgets/content/editorTest/test.js:212
select(0)@:0
initEditor([object Event])@chrome://xulwidgets/content/editorTest/test.js:382
@:0
This stack is interesting. noDeepSerialize is calling nsIDOMTreeWalker.nextNode(). Through the depths of C++ code, this tree walker, which in walking the tree isn't supposed to change it (that's supposed to be something I do after nextNode has returned), is causing an attribute to be set. This in turn fires a mutation event listener I've registered on the JavaScript side, which expects something to be there that isn't.
So something, from my point of view as a chrome developer, is bonkers in the C++ code. But what?
To figure this out, you need to stop the program. Enter nsIDebug. Deprecated as it is, it's easy to write a function for chrome that will fire the assertion. I recommend calling this function only when you can absolutely prove JavaScript code isn't the cause, and then calling it only from Venkman's command line.
function assertWithStack()
{
try {
throw new Error("Traditional JS stack dump");
}
catch (e) {
dump("\n\n");
dump("Traditional JS stack dump\n");
dump(e.stack);
dump("\n\n");
}
var realFrame = Components.stack.caller;
var nsIDebugService = Components.classes["@mozilla.org/xpcom/debug;1"]
.getService(Components.interfaces.nsIDebug);
nsIDebugService.assertion("A script is claiming bad things are happening!", false, realFrame.filename, realFrame.lineNumber);
}
It still works. (If anyone wants to remove this path for JavaScript crashing the program, I will be upset.)
So when I had a problem that Venkman couldn't solve, I called this function. The result was a depressingly long and incomprehensible C++ stack. Worse, it's not terribly useful in telling you what JavaScript frames you have. I've posted my best guess stack at where the JavaScript functions intermingle in the C++ stack. With a little help, it's pretty easy to narrow down the cause to about eight frames.
I would pay real money to have a open-source debugger that could properly debug Mozilla-based application across the language barriers. I strongly suspect others would be willing to pay, too. The debugger would go from C++ lines to JS by going up and down one frame in the stack, and you'd get all the appropriate values too. C++ debuggers obfuscate what the scripts are doing, and JS debuggers have no chance of seeing what's going on in the C++ world. We need a cross-language debugger.
At a rough guess, I envision such a debugger would be XULRunner-based and able to attach to any (other) debug Mozilla build that's currently running. Beyond that, I have no idea how such a debugger would work.
Call it XPDebugger if you want. I would gladly contribute personal time and some of my salary to getting a good tool built. I'd love to see a proposal take shape through wiki, through newsgroups, whatever, to create a XPCOM debugger. Venkman's great for debugging JS. Maybe it'd be a good starting point for a more advanced and useful XPDebugger, at least in terms of user interface.
Random notes in summary:
UPDATE: timeless has explained to me the existence of DumpJSObject from a C++ debugger. I am not impressed, because this makes my job as a debugger only slightly more helpful.
He also says it would take about a week for a sufficiently available and qualified developer. Those who he considers qualified are among the busiest of mozilla.org's contributors. Me, I'm more skeptical. I don't think it's that easy at all.
While doodling on a pad today thinking about user interfaces, I started to wonder how I could demonstrate by UI that two sets overlapped and had common members. (In DOM parlance, this would be two ranges overlapping in the same document, or two overlapping selections.) Given a DOM node tree, how would you show that a node belongs to two different ranges? My solution: add in a few narrow columns to the left, and shade the columns by row for each selection. If two ranges overlap (or have adjacent boundaries), then put each range shading in different columns.
In other words, just add bars to the left of the main objective to show where the sets and their overlaps are.
So far, so good. But at the same time, I had this "brilliant" idea: why not make each selection's shading in the column a different color? Read on for more details.
Of course, they couldn't be just different. #ffffff is different than #fffffe, but I dare you to look at a webpage with a background of pure white and a fair-sized square of this odd color, and tell me where the square is, using only your eyes (no mouse, no keys). No, they had to be as different as possible so that people could recognize each one.
(These unique selections would also have unique number codes in them, as another aid.)
So instead of the 1.6 million plus colors I could choose from, I decided to restrict myself to the "web-safe" colors. But then how would I choose colors that were the most distinct from one another, so that a little 10-pixel-square marker could clearly be distinguished from another.
Enter combinatorics, the well-known art of mathematics where you try to find as many combinations as you can of something. (For fans of PBS, I first heard about this on the show "Square One", which I still think is one of the best shows there could have been for a young elementary school student.) There are six generally recognized web-safe levels of color intensity: 00, 33, 66, 99, CC, and FF. There are three types of colors the computer monitor shoots through electron guns: red, green and blue. Combinatorics tells us, then, there are 216 possible web-safe colors (six to the third power).
But combinatorics wouldn't help me define a preferred order to these colors. At least, not in so simple a calculation.
I then started drawing up a table of two axes, one for a "on" color and one for a "off" color. My thinking was the most diverse combinations of color intensities (brightness) would produce the most distinct colors. #ffffff compared to #000000 is much more distinct than #ffffff compared to #cccccc, for example. So for a pair of on-off brightness values, there would be eight combinations (on-off for red times on-off for green times on-off for blue). But how to select the most distinct pairs?
At this point, I started throwing numbers on the table, making intuitive guesses. Almost half the table I threw out immediately, since an on-off pair reversed would match another on-off pair, and give me duplicate results. Also, where on and off matched, there could be no pairs. I wrote up an algorithm that would give me about 120 colors in an order that probably would start with the most distinctive colors, and descend to colors that grew a little too close for my comfort. Since in most cases I couldn't imagine anyone using more than about, oh, 32 of them at any given time, I figured this would be more than enough.
Until I started thinking about the possibility that I was ignoring some combinations.
The above on-off idea means you could have combinations like #ff00ff and #99cccc, but it would exclude combinations like #33ffcc. So I started over on a new sheet of paper. I assumed three levels of brightness. Harkening back to my days in high school television, I called these three key, back, and fill (for the three main lights used in lighting a subject for the camera). The key, or primary, would always be ff. The back light and fill lights would be any of the other five brightness levels. This meant a table of 25 options, of which 10 had to be discarded right away (again, one back-fill pair would be another's fill-back pair, and mean more duplicates.) That left fifteen options of up to twenty-seven different colors. I discarded six where the combinations just seemed too close, and ended up with nine sets of 27 -- potentially 243 colors in all.
Now, if I had my wits about me at that moment, I probably would have realized that I had too many colors. There are only a possible 216 web-safe colors, where I was claiming to have found 243 candidates. It didn't take me long to realize another flaw, though: where the back and fill colors matched, there were only 8 possible color combinations (not 27). Take that into account, and I still had an algorithm for finding and ordering 148 relatively distinct colors.
(I think my math is still off here. 148, when you consider the earlier guess of 120, seems too low.)
So I had two algorithms which would likely yield me good orders for colors, at least at the front of the pile. Somewhere in the final bus ride home, I realized the biggest fallacy of all with regard to this little scheme, and it had nothing to do with mathematics or intuitive guessing.
In a perfect world, where everyone could see all these colors, it would have been a very good solution. Certainly it would have been more than adequate in either variation for my purposes. But we don't live in a perfect world. We live in a human world, with human frailties, such as color-blindness.
Now, when I work on user-interfaces, I generally want them to be accessibility-friendly. This means taking into account a lot of different things, such as color-blindness. Some of the colors my algorithm would have generated, to at least one family member of mine, would have appeared identical. This completely defeats the scheme of multi-color highlighting, as I originally imagined. It was a "brilliant" idea, but an impractical one.
Not all is lost. I can still give each selection the standard dark-blue selection highlighting (and a background of white for non-selected portions), plus a little number code in the highlight identifying the selection.
The best part about this mistake I made is that it cost me only a couple hours of deep thinking in an area I've never been great at within the realm of mathematics and logic. It was good practice, too. I'm not really writing this blog to say, "Woe is me, I'm a dumb guy again." But I am writing it to say, "Here's another mistake you can learn from."
Overall, I don't regret going down this path, as I often do when I make fundamentally wrong assumptions. I learned a little bit more about good UI design. What I've just explained has probably been covered in UI design books before, but it bears thinking about by programmers in general.
This is an automatically generated Delivery Status Notification
Delivery to the following recipient failed permanently:
ben@***.com
Technical details of permanent failure:
PERM_FAILURE: SMTP Error (state 9): 554 : Recipient address rejected: Access denied
I just wanted his expert opinion on something... :-)
Having jumped off a cliff before on religion (and regretting it), I'm going to do something similarly inflammatory. I'm going to discuss American politics.
If you care, go ahead and read the full article.
For years, I've wondered about the feasibility of adding a presidential line-item veto to the Constitution of the United States of America. Every now and then, you hear about the line-item veto in the news, but there's not much seriousness to it.
I won't rehash old arguments on it; I strongly support it as a matter of principle and would like to see it happen.
A quick search on the Library of Congress website shows there is an amendment offered in the U.S. House of Representatives. It's apparently stuck in committee.
Not being a lawyer, I don't know what it would take (beyond the details available in the Constitution itself, Article V, for an amendment; I'm not that dumb) to get the bill acted on and sent to the Congress for a full vote. But I would like to see it happen.
I'm probably going to write my congressional representative about it. If you feel this is a good thing, you might want to write your rep too.
Here at the office, I gathered everything I knew about XPI's and confidently predicted that I could alter our new XPI packages to work with Firefox (they already work with SeaMonkey) in about a day. While that assertion still seems correct, it's extremely annoying that I have to do so many things just to get it working.
SeaMonkey kept it simple: install.js and a few contents.rdf files, and on you go.
Firefox requires a few more files:
On top of that, the changes to the chrome package names make life really interesting. Now I have to overlay both chrome://navigator/* and chrome://browser/* as well.
I realize fully that at the time these "features" were implemented, SeaMonkey was not taken seriously by anyone but a few devotees (like myself). I also realize that SeaMonkey isn't a primary project anymore. I'm just griping, and I need to convince my boss to allocate some of my time officially to general SeaMonkey- and core bugfixing.
I'm not complaining that Aviary went and did their own thing. I'm complaining that the two are really out of sync. I don't care which path either Aviary or SeaMonkey takes, just as long as they're consistent.
Ah, well, maybe for SeaMonkey 2.0/3.0.
UPDATE: People are rapidly responding, touting the benefits of the Aviary API. Amen, I say to you, that's not my point. My point, as a corporate extension developer, is that I shouldn't need to work much harder to support both Firefox and SeaMonkey. I'd welcome as much as anyone else efforts to update SeaMonkey's codebase to support the new API on trunk. (For the record, I do generally think the new API is better than the old one.)
My new best friend, smaug ;-), posted a serious cleanup of DOM events code recently (see bug 234455 for details), thus allowing me to considerably simplify a patch for a bug that's blocked me on Verbosio for months (bug 201236). That one looks like it's going to be finished up fairly soon, too, so I was a happy camper.
Until this evening. Since Verbosio potentially can edit XUL applications, I figured I'd try a new approach: start with your most basic XUL editor possible. Specifically, a textbox and a script to take that textbox's contents, and replace the source code of the document with the textbox's value. The idea was to see if I could start to slowly build a more complex editor using the basic editor itself as I went.
That didn't work, for one simple reason: I couldn't get the source code of the script inside the XUL document. So I did a little digging, and discovered there were no child nodes for the script element...
*insert ex-sailor's swearing here*
Bug 330426. I'm back where I started -- worse, actually, since this is in a part of the code where I have no references to compare to. Other than the DOM specs, and they're the only justification I have for filing a bug.
One of the reasons I even thought about writing a native XPath Generator for Mozilla-based applications is a need to take a XPath for a DOM tree and translate it into a path for a DOM Inspector-like node tree. Unfortunately, as my mind has just now started wandering back towards my Verbosio application (for which I would use this XUL tree), I realized I had completely forgotten to include any functionality in the IDL or in the implementation for creating a XPath that would be friendly to this.
Specifically, I wanted a XPath that looks like: /node()[5]/node()[7]/node()[11]. I didn't think about that when writing the extension, though. Fortunately, I had a lot of foresight in allowing for extensibility. So, pending reviews to land the xpathgen code (which I don't expect right away), I'll submit a new bug to to "GET_CHILD_INDEXES_ONLY".
I might argue that I own the spec and I can do what I want there, but I don't buy that. I'm doing this for the community, so even when I suggest a new idea for the spec, I make sure to run it by someone else for approval.
UPDATE: Or maybe not. Collecting adjacent text & cdata nodes under XPath makes it not so useful.