Spammers try to look smart to fool us, but they really aren't. Reference this little gem that got past GMail's filters:
X-Gmail-Received: 7027b24f257865b549f0520a5e00633c137aa01b
Delivered-To: *********@*********
Received: by 10.65.96.5 with SMTP id y5cs41366qbl;
Tue, 21 Feb 2006 12:23:38 -0800 (PST)
Received: by 10.65.155.19 with SMTP id h19mr1741150qbo;
Tue, 21 Feb 2006 12:23:38 -0800 (PST)
Return-Path: <%CUSTOM_FINANCIAL_TERMS@gmail.com>
Received: from DM ([208.65.60.56])
by mx.gmail.com with SMTP id e14si27530qba.2006.02.21.12.23.38;
Tue, 21 Feb 2006 12:23:38 -0800 (PST)
Received-SPF: neutral (gmail.com: 208.65.60.56 is neither permitted nor denied by domain of %CUSTOM_FINANCIAL_TERMS@gmail.com)
Received: from %RND_HOST (8.8.8/8.8.8) id XAA59962; Tue, 21 Feb 2006 14:23:46 -0600
Message-Id: <170014510459.XAA13898%CUSTOM_FINANCIAL_TERMS@gmail.com>
From: "Nikhil Ball" <%CUSTOM_FINANCIAL_TERMS@gmail.com>
To: *********@*********
Subject: Concerning February Account Details
X-Mailer: Opera/7.02 (Windows ME; U)
Date: Tue, 21 Feb 2006 14:23:46 -0600
%CUSTOM_TO_ALIAS,
%CUSTOM_ACCOUNT - %CUSTOM_LINK
Nikhil Ball, Account Rep. %CUSTOM_REP_NUMBER
Mr. Ball -- or whoever you really are -- when are you going to realize:
On the plus side, you did get past the filter. I did read your e-mail. The GMail one-line summary was amusing enough to prompt me to see what was going on.
Bottom line: if you want to defraud me, you're going to have to work harder than a simple form letter. As many people with so-called dearly departed and super-rich relatives have found out.
I've had so much trouble over the last several days writing the XPath Generator algorithms that I started thinking. As a JavaScript expert and a C++ rookie, someone who knows IDL and can write components in JS with little trouble at all, there's really no quick page that summarizes how you write XPCOM code in different languages.
So this is a starting attempt to write such a document. The goal is to come up with a bunch of simple tasks component authors must do, and write snippets of code demonstrating each of these in IDL, C++, JavaScript, maybe Python or Perl, etc. Suggestions (and especially cross-language examples!) welcome.
I've written the document in generic XML for now, just to give me a simple framework for adding Q & A for each one. Eventually, as this document evolves, we can transform it for DevMo to adopt. I'll make sure to cite each contributor. Links to currently-existing-and-accurate documentation would be nice.
I've just completed a first-draft, unstable, patch implementing a XPath generator in native mozilla.org code. (It is highly unstable, so unless you're a developer willing to help fix bugs in it, don't use it.) It's been a marathon for me, writing a component from scratch with (until now) only peripheral experience in C++. I'm sure there are many in #developers who can attest to the large number of first-timer mistakes I've begged for help on.
As for the title of this blog entry, I'm pretty sure it's accurate. First, you start off with a lot of pain. Read the "Full Article" link for a list.
#ifdef DEBUG
const char* realHash = NS_LossyConvertUTF16toASCII(hashKey).get();
printf("hashKey: '%s'\n", realHash);
#endif
All this, just for the first draft. An experienced C++ developer reading this will probably chuckle ruefully at having gone down this sort of road before. What makes this so much harder for me is that this is literally my first attempt at writing a major C++ based tool. Until now, my major tools have been chrome or JavaScript-based tools. I've done smaller fixes in C++ code before (I implemented Attr.isId specifically for the XPath generator). But for me, this is a giant leap. Believe me, I'm not Superman.
As for the working-out analogy: You start out with a lot of pain. The exercises are not fun. When you go home at the end of the first day, you're sore, tired, and thinking you don't want to go back. But you go back anyway, because you know it's the right thing to do.
A few days later, you're doing better. You're starting to get a feel for how it's done. The workouts start becoming easier. You come back with better abilities, and you don't have to ask for help on every little thing. You start to experiment, try to lay down some patterns to follow.
Finally, it becomes so routine that you look for ways to branch out and do other stuff. You don't have to ask for help; you just do it, and you feel good. Really, really good. Pretty soon, you're casually talking with other people just starting out, giving them little tips from your own experience where you made a big mistake and paid for it.
That's where the analogy ends for me; I haven't gotten further in my gym workouts than this third stage, so I can't explain how it feels. On C++, I'm probably at the second stage. There are probably four or five other stages in the pipeline, some in between the stages I list here, but you get the idea. It's a lot of work. But ultimately, it does pay off.
With that, I'm going to bed. I think that, when all is reviewed and super-reviewed, I will finally go get the CVS checkin privileges which I would need to land this patch. It's just time.
A few weeks ago, bz helped me solve one of the issues blocking content-to-chrome messaging. Unfortunately, as I have just discovered, that's not enough.
I tried giving my little nsIDOMEvent object a few JS properties from content. Little things, like a string (evt.foo = "bar"). But when the event reached my chrome event listener, that property was not available.
Whoops. I still need to figure out the solution to the original problem: getting a meaningful message across. My fault for not being clear enough in my original request. Help still wanted!
For what it's worth, I was making pretty good progress hacking XPathGenerator together so far. I have the revamped resolver working now. (Many, many thanks to biesi, timeless, bz and peterv for offering compile/link/crash fixes as I go along.)
UPDATE: My approach (a custom IDL + JS component) seems to be working quite nicely. When I have it fully fleshed out, I'll try to get that part of the code released to open-source. (ManyOne probably owns the code, even if I wrote it.)
In designing an initial implementation of XPathGenerator, I decided I'd try first to implement it as a JavaScript-based component with a few special-case C++ functions included. The idea was to make it more generic than normal, so that converting from one language to another would be somewhat easier on my soul. The code wouldn't have been review-ready at first, but if I could make it work in JS, it'd be relatively simple to drop the less-than-relevant portions.
There's some wisdom to that approach now, it seems. This evening, I hit upon a new situation entirely. In executing alert(typeof JSXPathGenerator) (a test name for the component's implemented XPathGenerator constructor), I got something I'd never seen before: a QueryInterface call with an IID that isn't in Components.interfaces.
A little quick research and a modified dump() statement led to nsIDOMCIExtension. This defines a fair number of little macros that don't make any sense at all until you look at the XML Extras module & factory code. Even then, it makes very little sense to me.
So, in other words, after all my initial work, it appears there's no easy way to create a JS-based XPCOM component to deliver a constructor. Now, if someone would translate nsIDOMCIExtension's macros into something more cross-language friendly, I wouldn't have this problem. Or if there was a JS equivalent (I'm not in the mood to do the translation), I could keep going.
But back to the original topic. I'm trying to decide whether to pursue this in JavaScript or C++.
WeirdAl bz: let me rephrase. I'm trying to find the path of least resistance to implementing this thing. WeirdAl if that path is C++, then so be it. bz_sleep finds all paths involving creating new components to have high resistance. ;)
So, at least for the moment, I'm in a pit. I'll be starting over from C++ fairly soon, unless someone's nice enough to figure out the nsIDOMCIExtension code and write some new code to support me there. At least the JS code gives me a partial mock-up to follow.
Overall, unlike my previous blog entry, I find this amusing.
Oh, one more thing: the typeof call, because of the XPCOM error, didn't pop up any dialog at all, not even "undefined". I have filed as bug 325707.
UPDATE: Thanks to peterv, timeless, and #developers, I've got a C++-based constructor component built. It doesn't do anything yet, but you can construct objects from it. Reference bug 319768, comment 21 for the patch.
When I'm developing a new chrome package, I like to specify that I support both the classic and modern skins. So, in skin/contents.rdf, I would by default write:
<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
<RDF:Seq about="urn:mozilla:skin:root">
<RDF:li resource="urn:mozilla:skin:classic/1.0"/>
<RDF:li resource="urn:mozilla:skin:modern/1.0"/>
</RDF:Seq>
<RDF:Description about="urn:mozilla:skin:classic/1.0">
<chrome:packages>
<RDF:Seq about="urn:mozilla:skin:classic/1.0:packages">
<RDF:li resource="urn:mozilla:skin:classic/1.0:xulwidgets"/>
</RDF:Seq>
</chrome:packages>
</RDF:Description>
<RDF:Description about="urn:mozilla:skin:modern/1.0">
<chrome:packages>
<RDF:Seq about="urn:mozilla:skin:modern/1.0:packages">
<RDF:li resource="urn:mozilla:skin:modern/1.0:xulwidgets"/>
</RDF:Seq>
</chrome:packages>
</RDF:Description>
</RDF:RDF>
Naturally, I keep all my skin contents under skin/, right alongside the contents.rdf file. So, for some reason, chrome://xulwidgets/skin/contents.rdf fails.
Some debugging time later, I look in dist/bin/chrome/chrome.rdf and discover the following:
<RDF:Description RDF:about="urn:mozilla:skin:modern/1.0:xulwidgets"
c:baseURL="jar:resource:/chrome/xulwidgets.jar!/xulwidgets/skin/modern/1.0"
c:allowScripts="false">
<c:package RDF:resource="urn:mozilla:package:xulwidgets"/>
</RDF:Description>
The baseURL attribute is totally bogus. It should have been c:baseURL="jar:resource:/chrome/xulwidgets.jar!/xulwidgets/skin/". So what happened?
The code for nsChromeRegistry.cpp assumes that if I provided more than one skin package listing in the contents.rdf file, I must have provided the skins in the subdirectories. It also assumes that if I provided exactly one such entry, the skin lives in the current directory.
What annoys me about this is that it gives the package developer (me) a false impression. I can't explicitly state I support more than one skin without having lots of duplicate files. There's also no immediately obvious way for me to force Mozilla to accept a different base URL (say, the correct one) through contents.rdf.
This is really not cool. This is one of the issues that has bitten me again and again over the years because it's not documented anywhere, and I finally lost my patience with it today. I remember having this problem when I first started developing Abacus, about three years ago. If there's a better way to do this, I'd really like to know what it is. Or if there's a bug on file about it, I'd like to know about that too.
UPDATE: I guess it would sort of make sense as currently implemented, if each individual skin had its own contents.rdf, and the install.js/rdf file referred to each individual contents.rdf file. But it's still not nice.