<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>0xDECAFBAD - Tag: greasemonkey</title>
    <link href="http://decafbad.com/blog/atom.xml" rel="self"/>
    <link href="http://decafbad.com/blog"/>
    <updated>2011-11-16T16:29:50+00:00</updated>
    <id></id>
    <author>
        <name></name>
        <email>l.m.orchard@pobox.com</email>
    </author>
    

    <entry>
        <title>Writing a Delicious command for Ubiquity</title>
        <link href="http://decafbad.com/blog/2008/09/01/writing-a-delicious-command-for-ubiquity"/>
        <updated>2008-09-01T04:37:03+00:00</updated>
        <id>http://decafbad.com/blog/2008/09/01/writing-a-delicious-command-for-ubiquity</id>
        <content type="html">&lt;p&gt;In my &lt;a href=&quot;http://decafbad.com/blog/2008/08/31/ubiquity-cracks-open-personal-mashup-tinkering&quot; title=&quot;Ubiquity cracks open personal mashup tinkering&quot;&gt;last post&lt;/a&gt;, I got all fluffy about how cool &lt;a href=&quot;http://labs.mozilla.com/2008/08/introducing-ubiquity/&quot;&gt;Ubiquity&lt;/a&gt; is but didn't share any code to prove the point.  As it happens, I have come up with at least one useful command that I'm starting to use habitually in posting bookmarks to Delicious.  You can &lt;a href=&quot;http://decafbad.com/UbiquityCommands/&quot;&gt;subscribe to my command&lt;/a&gt; or &lt;a href=&quot;http://decafbad.com/hg/UbiquityCommands/file/tip/delicious.ubiq.js&quot;&gt;check out the full source&lt;/a&gt;—this post will serve as a dissection of the thing.  Since this will be fairly lengthy, follow along after the jump.&lt;/p&gt;

&lt;p&gt;Oh, and it's been awhile since I posted something this in-depth around here, so feel free to let me know how this first draft works.  And, bug reports and patches are of course welcome.&lt;/p&gt;

&lt;!--more--&gt;


&lt;p&gt;To begin, consider the following code starting off the command source code:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;1&quot;&gt;
/**
 * share-on-delicious - an Ubiquity command for sharing bookmarks on
 * delicious.com
 *
 * l.m.orchard@pobox.com
 * http://decafbad.com/
 * Share and Enjoy!
 */
var uext = Application.extensions.get('ubiquity@labs.mozilla.com');

var cookie_mgr = Components.classes[&quot;@mozilla.org/cookiemanager;1&quot;]
    .getService(Components.interfaces.nsICookieManager);
&lt;/pre&gt;


&lt;p&gt;The first thing to note here is that a short header comment introduces the command.  This isn't required, but it's a good idea.  It's also something you can't really do with bookmarklets.  On the other hand, Greasemonkey user scripts expect metadata about the script to be provided here, but Ubiquity doesn't use this convention.&lt;/p&gt;

&lt;p&gt;Second, notice that the code accesses some chrome-level resources.  Again, this is something unavailable to bookmarklets and Greasemonkey user scripts.  Just take a look at the &lt;a href=&quot;http://developer.mozilla.org/en/FUEL&quot;&gt;FUEL library documentation&lt;/a&gt; to get a quick sense of what's available using that simplified API, not to mention what's available using the lower-level browser APIs.&lt;/p&gt;

&lt;p&gt;Now, check out this next chunk of code, which begins the construction of an Ubiquity command:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;13&quot;&gt;
CmdUtils.CreateCommand({
    
    name:        
        'share-on-delicious',
    icon:
        'http://delicious.com/favicon.ico',
    description: 
        'Share the current page as a bookmark on delicious.com',
    help:        
        'Select text on the page to use as notes, or enter your own ' + 
        'text after the command word.  You can also assign tags to the '+ 
        'bookmark with the &quot;tagged&quot; modifier, and alter the bookmark ' + 
        'default page title with the &quot;entitled&quot; modifier.  Note that ' + 
        'you must also already be logged in at delicious.com to use ' +
        'this command.',

    homepage:   
        'http://decafbad.com',
    author: { 
        name: 'Leslie Michael Orchard', 
        email: 'l.m.orchard@pobox.com' 
    },
    license:
        'MPL/GPL/LGPL',
&lt;/pre&gt;


&lt;p&gt;Whereas Greasemonkey scripts support metadata in the header comment, the Ubiquity command script API works a little differently.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://hg.toolness.com/ubiquity-firefox/file/tip/ubiquity/chrome/content/cmdutils.js&quot;&gt;&lt;code&gt;CmdUtils&lt;/code&gt; module&lt;/a&gt; provided by Ubiquity offers a &lt;code&gt;CreateCommand&lt;/code&gt; function, which expects an object as a parameter.  The object literal whose construction is begun in the code above serves as a self-contained package for the command, bearing metadata describing the command as well as containing all the code necessary to implement it.&lt;/p&gt;

&lt;p&gt;So, in the above code block, you can see the machine-readable description of the command—including a command name, display icon, home page URL, author information, and license.  The command name (&lt;code&gt;share-on-delicious&lt;/code&gt;) will be used by the Ubiquity command parser, but the rest of the description will also be used in the list of commands available to the user, invoked by the &lt;code&gt;command-list&lt;/code&gt; command, like so:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/2008/ubiq-share-on-delicious-list.jpg&quot; style=&quot;border: 1px solid #333; margin: 0.25em; padding: 0.25em&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Moving along, this next chunk of code introduces the first functional bits of the command:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;37&quot;&gt;
    takes: { notes: noun_arb_text },
    modifiers: { 
        tagged:  noun_arb_text,
        entitled: noun_arb_text
    },
&lt;/pre&gt;


&lt;p&gt;Like smart keyword shortcut bookmarks, Ubiquity commands accept user-supplied input.  But, what's unique to Ubiquity is that it employs a parser whose goal is to support something approximating natural language.  At present, this results in commands that support a single primary argument—declared above with the &lt;code&gt;takes&lt;/code&gt; property—and any number of additional keyword modifiers—declared above by the &lt;code&gt;modifiers&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;For the command under construction here, this establishes a pattern something like the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;share-on-delicious {notes} [tagged {tags} entitled {title}]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Content for the &lt;code&gt;{notes}&lt;/code&gt; argument can either be typed directly by hand, or it can be supplied by text highlighted on the page.  To use highlighted text, you can either issue the command alone, or use the word &lt;code&gt;this&lt;/code&gt; for the &lt;code&gt;{notes}&lt;/code&gt; argument before including further modifiers.&lt;/p&gt;

&lt;p&gt;The modifiers &lt;code&gt;tagged&lt;/code&gt; and &lt;code&gt;entitled&lt;/code&gt; are optional, and can be used in any order.  Each of these keywords signifies the start of a different argument—which unfortunately can collide with the literal data supplied for notes, which will hopefully be a rare occurrence.&lt;/p&gt;

&lt;p&gt;All of this adds up command invocations including the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;share-on-delicious
share-on-delicious I really like this page tagged nifty amusing
share-on-delicious this entitled This bookmark has no tags
sh this tagged osx software apple entitled This is good OS X software
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That last example is important—since I have no other commands starting with &quot;&lt;code&gt;sh&lt;/code&gt;&quot;, I can abbreviate the full command.  Ubiquity only requires enough of a command name to disambiguate it within your collection of commands.&lt;/p&gt;

&lt;p&gt;Another thing to note is the use of the constant value &lt;code&gt;noun_arb_text&lt;/code&gt;, which declares that these arguments should expect any arbitrary text as input.&lt;/p&gt;

&lt;p&gt;This facility is not exploited for the present command, but Ubiquity defines &lt;a href=&quot;http://hg.toolness.com/ubiquity-firefox/file/tip/ubiquity/chrome/content/nlparser/en/nountypes.js&quot;&gt;noun types&lt;/a&gt;.  These include concepts such as plain text, dates, address book contacts, browser tabs, bookmark tags, and more.  You can define your own noun types, as well as implement suggestion schemes that help guide the user toward constructing useful input values in the command interface.  You can &lt;a href=&quot;https://wiki.mozilla.org/Labs/Ubiquity/Ubiquity_0.1_Author_Tutorial#Introduction_to_Noun_Types&quot;&gt;read more about this&lt;/a&gt; in the official author tutorial.&lt;/p&gt;

&lt;p&gt;Next up is a quick bit of command-specific configuration:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;42&quot;&gt;
    /**
     * Command configuration settings.
     */
    _config: {
        // Base URL for the delicious v1 API
        api_base:      'https://api.del.icio.us',

        // Domain and name of the delicious login session cookie.
        cookie_domain: '.delicious.com',
        cookie_name:   '_user'
    },
&lt;/pre&gt;


&lt;p&gt;Since this command will be posting to Delicious via the V1 API, it's handy to declare the base URL for the API in an easily changed spot.  That way, you could change this value later on to point the command at another implementation of the API.&lt;/p&gt;

&lt;p&gt;Additionally, this command will employ a little-known authentication trick supported by the Delicious API that accepts the user's login cookie set by the Delicious website—this &quot;cookie god&quot; auth is used by the official Delicious addon for Firefox.  It's handy for piggybacking on the website login and removing the need to ask the user for their username and password again and possibly storing it in an insecure manner.&lt;/p&gt;

&lt;p&gt;In fact, this next chunk of code defines a utility method to rummage through the cookie jar:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;53&quot;&gt;
    /**
     * Dig up the Delicious login session cookie.
     */
    _getUserCookie: function() {
        var iter = cookie_mgr.enumerator;
        while (iter.hasMoreElements()) {
            var cookie = iter.getNext();
            if( cookie instanceof Components.interfaces.nsICookie &amp;&amp; 
                cookie.host.indexOf(this._config.cookie_domain) != -1 &amp;&amp; 
                cookie.name == this._config.cookie_name) {
                return decodeURIComponent(cookie.value);
            }
        }
    },
&lt;/pre&gt;


&lt;p&gt;The method defined above, &lt;code&gt;._getUserCookie()&lt;/code&gt;, uses the browser's cookie manager and the values defined in the previous configuration section to find the login session cookie set for Delicious.  Take note that this is far beyond the allowed capabilities of bookmarklets and Greasemoney user scripts—this is digging straight into the browser itself, skipping past the usual content-space security restrictions.&lt;/p&gt;

&lt;p&gt;In other words: In Ubiquity, &lt;em&gt;the gun is loaded&lt;/em&gt; and you should be careful.&lt;/p&gt;

&lt;p&gt;Moving along, consider this next utility method:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;67&quot;&gt;
    /**
     * Given input data and modifiers, attempt to assemble data necessary to
     * post a bookmark.
     */
    _extractBookmarkData: function(input_obj, mods) {
        return {
            _user:
                this._getUserCookie(),
            url:
                context.focusedWindow.location,
            description:
                mods.entitled.text || context.focusedWindow.document.title,
            extended: 
                input_obj.text,
            tags:
                mods.tagged.text
        };
    },
&lt;/pre&gt;


&lt;p&gt;Named &lt;code&gt;._extractBookmarkData()&lt;/code&gt;, this utility method accepts the results of Ubiquity's parser interpreting the primary argument and modifier arguments supplied by the user.  Using these data structures, it attempts to build a structure representing the fields of a Delicious bookmark.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;_user&lt;/code&gt; field is used for authentication via the site login cookie.  The &lt;code&gt;url&lt;/code&gt; is set from the location bar of the current page.  The &lt;code&gt;description&lt;/code&gt;, or title, field of the bookmark is taken from either the &lt;code&gt;entitled&lt;/code&gt; modifier or the title of the current page.  The &lt;code&gt;tags&lt;/code&gt;, if any, come from the &lt;code&gt;tagged&lt;/code&gt; modifier.  And, finally, the &lt;code&gt;extended&lt;/code&gt; notes for the bookmark are taken from the primary input argument of the command.&lt;/p&gt;

&lt;p&gt;As you'll see shortly, this utility method will be used in both the preview and the execution of the command.&lt;/p&gt;

&lt;p&gt;Next, there's one more utility method to cover:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;85&quot;&gt;
    /**
     * Given an object, build a URL query string
     */
    _buildQueryString: function(data) {
        var qs = [];
        for (k in data) if (data[k]) 
            qs.push( encodeURIComponent(k) + '=' + 
                encodeURIComponent(data[k]) );
        return qs.join('&amp;');
    },
&lt;/pre&gt;


&lt;p&gt;In anticipation of using the Delicious V1 API, the &lt;code&gt;._buildQueryString()&lt;/code&gt; method accepts an object and constructs a URL query string from the encoded properties of the object.  This will be paired with the &lt;code&gt;._extractBookmarkData()&lt;/code&gt; method to supply data for API calls.&lt;/p&gt;

&lt;p&gt;Moving along, it's time to start digging into the meat of this Ubiquity command:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;95&quot;&gt;
    /**
     * Present a preview of the bookmark under construction during the course
     * of composing the command.
     */
    preview: function(pblock, input_obj, mods) {

        var bm          = this._extractBookmarkData(input_obj, mods);
        var user_cookie = this._getUserCookie();
        var user_name   = (user_cookie) ? user_cookie.split(' ')[0] : '';

        var ns = { user_name: user_name, bm: bm };
        var tmpl;
&lt;/pre&gt;


&lt;p&gt;With this code, the implementation of command method &lt;code&gt;.preview()&lt;/code&gt; has begun.  This method is used by Ubiquity to generate a live preview of the command.  Called with a DOM node (&lt;code&gt;pblock&lt;/code&gt;) and partially completed command input (&lt;code&gt;input_obj&lt;/code&gt; and &lt;code&gt;mods&lt;/code&gt;), this method is expected to build a representation of the command's results in the DOM node.  As the user types, this method will be called over and over again, ideally offering feedback as the user composes a command.&lt;/p&gt;

&lt;p&gt;Continuing on, consider this next chunk of code checking the validity of command input:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;107&quot;&gt;
        if (!user_name) {

            // If there's no user name, there's no login, so this command won't work. 
            tmpl = [ 
                '&lt;p style=&quot;color: #d44&quot;&gt;No active user found - log in at ', 
                '&lt;img src=&quot;http://delicious.com/favicon.ico&quot;&gt; ',
                '&lt;b&gt;&lt;a style=&quot;color: #3774D0&quot; href=&quot;http://delicious.com&quot;&gt;delicious.com&lt;/a&gt;&lt;/b&gt; ', 
                'to use this command.&lt;/p&gt;'
            ].join('');

        } else if (!bm.description) {

            // If there's no title, then this is an error too.
            tmpl = [ 
                '&lt;p style=&quot;color: #d44&quot;&gt;A title is required for bookmarks on ', 
                '&lt;img src=&quot;http://delicious.com/favicon.ico&quot;&gt; ',
                '&lt;b&gt;&lt;a style=&quot;color: #3774D0&quot; href=&quot;http://delicious.com&quot;&gt;delicious.com&lt;/a&gt;&lt;/b&gt; ', 
                '&lt;/p&gt;'
            ].join('');
&lt;/pre&gt;


&lt;p&gt;This chunk of code first checks for a user name, which can be extracted from a valid Delicious login cookie, if one was found.  If not found, the command will fail—so the preview built here will instruct the user to login at Delicious before going further.&lt;/p&gt;

&lt;p&gt;The second precondition for using the command is that the bookmark has been given a title.  By default, this is the title of the current page—but, some pages don't offer titles.  So, an error needs to be flagged if the user hasn't manually supplied a title in this case.&lt;/p&gt;

&lt;p&gt;Finally, notice in both of these error cases, a string of HTML is composed in the variable &lt;code&gt;tmpl&lt;/code&gt;.  This will be used at the end of the method to populate the DOM node passed in as &lt;code&gt;pblock&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, assuming that all the command's prerequisites have been met, it's time to try constructing a proper preview for the results of this command:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;126&quot;&gt;
        } else {

            // Attempt to construct a vaguely delicious-esque preview of a bookmark.
            tmpl = [ 
                '&lt;style type=&quot;text/css&quot;&gt;',
                    '.preview a { color: #3774D0 }',
                    '.del-bookmark { font: 12px arial; color: #ddd; background: #eee; line-height: 1.25em }',
                    '.del-bookmark a.title { color: #1259C7 }',
                    '.del-bookmark .full-url { color: #396C9B; font-size: 12px; display: block; padding: 0.25em 0 }',
                    '.del-bookmark .notes { color: #4D4D4D }',
                    '.del-bookmark .tags { color: #787878; padding-top: 0.25em; text-align: right }',
                '&lt;/style&gt;',
                '&lt;div class=&quot;preview&quot;&gt;',
                    '&lt;p&gt;Share a bookmark at &lt;img src=&quot;http://delicious.com/favicon.ico&quot;&gt; ',
                        '&lt;b&gt;&lt;a href=&quot;http://delicious.com/${user_name}&quot;&gt;delicious.com/${user_name}&lt;/a&gt;&lt;/b&gt;:&lt;/p&gt;',
                    '&lt;div class=&quot;del-bookmark&quot;&gt;',
                        '&lt;div style=&quot;padding: 1em;&quot;&gt;',
                        '&lt;a class=&quot;title&quot; href=&quot;${bm.url}&quot;&gt;${bm.description}&lt;/a&gt;',
                        '&lt;a class=&quot;full-url&quot; href=&quot;${bm.url}&quot;&gt;${bm.url}&lt;/a&gt;',
                        bm.extended ? 
                            '&lt;div class=&quot;notes&quot;&gt;${bm.extended}&lt;/div&gt;' : '',
                        bm.tags ?
                            '&lt;div class=&quot;tags&quot;&gt;&lt;span&gt;tags:&lt;/span&gt; ${bm.tags}&lt;/div&gt;' : '',
                    '&lt;/div&gt;',
                '&lt;/div&gt;'
            ].join(&quot;\n&quot;);

        }

        pblock.innerHTML = CmdUtils.renderTemplate(tmpl, ns);
    },
&lt;/pre&gt;


&lt;p&gt;Building on the notion that previews are built in a DOM node, the code above uses both CSS and HTML to assemble a quick-and-dirty facsimile of a Delicious bookmark—which will be rendered like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/2008/ubiq-share-on-delicious-preview.jpg&quot; style=&quot;border: 1px solid #333; margin: 0.25em; padding: 0.25em&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Also note that Ubiquity provides a template engine for use in generating content—namely the &lt;a href=&quot;http://code.google.com/p/trimpath/wiki/JavaScriptTemplates&quot;&gt;JavaScript Templates&lt;/a&gt; engine from the &lt;a href=&quot;http://code.google.com/p/trimpath/wiki/TrimPath&quot;&gt;TrimPath&lt;/a&gt; project.  This engine may eventually be replaced with another, but the notion is that Ubiquity will provide tools to more easily generate previews and more.&lt;/p&gt;

&lt;p&gt;The conclusion of the &lt;code&gt;.preview()&lt;/code&gt; method uses the template engine with a call to &lt;code&gt;CmdUtils.renderTemplate()&lt;/code&gt; to inject content into the preview element by way of the &lt;code&gt;.innerHTML&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Now that the preview is out of the way, it's time to get down to implementing the execution of the command:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;157&quot;&gt;    
    /**
     * Attempt to use the delicious v1 API to post a bookmark using the 
     * command input
     */
    execute: function(input_obj, mods) {
        var bm          = this._extractBookmarkData(input_obj, mods);
        var user_cookie = this._getUserCookie();
        var user_name   = (user_cookie) ? user_cookie.split(' ')[0] : '';

        if (!user_name) {
            // If there's no user name, there's no login, so this command won't work. 
            displayMessage('No active user found - log in at delicious.com ' +
                'to use this command.');
            return false;
        }

        if (!bm.description) {
            // If there's no title, somehow, then this is an error too.
            displayMessage(&quot;A title is required for bookmarks at delicious.com&quot;);
            return false;
        }
&lt;/pre&gt;


&lt;p&gt;Mirroring the &lt;code&gt;.preview()&lt;/code&gt; method, the &lt;code&gt;.execute()&lt;/code&gt; method first checks for validity of the arguments given by the user.  A missing user name or title result in a notification that the command has failed.&lt;/p&gt;

&lt;p&gt;But, if the arguments are all valid, it's time to actually issue a request to the Delicious V1 API:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;178&quot;&gt;
        var path = '/v1/posts/add';
        var url  = this._config.api_base + path;

        var req = Components.classes[&quot;@mozilla.org/xmlextras/xmlhttprequest;1&quot;].
            createInstance();

        req.open('POST', url, true);

        req.onload = function(ev) { 
            displayMessage('Bookmark &quot;' + bm.description + '&quot; ' + 
                'shared at delicious.com/' + user_name);
        }

        req.onerror = function(ev) { 
            displayMessage('ERROR: Bookmark &quot;' + bm.description + '&quot; ' + 
                ' NOT shared on delicious.com/' + user_name);
        }
&lt;/pre&gt;


&lt;p&gt;Using the base URL for the Delicious API declared earlier in the configuration section, the &lt;code&gt;.execute()&lt;/code&gt; method constructs an API URL for the &lt;code&gt;/v1/posts/add&lt;/code&gt; method.  Then, it creates an instance of &lt;code&gt;XMLHttpRequest&lt;/code&gt; from the browser to be used in sending the API request.  Event handlers are registered with the object to present notifications to the user indicating whether or not the API request was successful.&lt;/p&gt;

&lt;p&gt;At long last, it's time to wrap up this method and make the API request:&lt;/p&gt;

&lt;pre lang=&quot;javascript&quot; line=&quot;195&quot;&gt;
        req.setRequestHeader('Authorization', 'Basic Y29va2llOmNvb2tpZQ=='); // btoa('cookie:cookie')

        var mediator = Components.classes[&quot;@mozilla.org/appshell/window-mediator;1&quot;].
            getService(Components.interfaces.nsIWindowMediator);
        var win = mediator.getMostRecentWindow(null);
        var user_agent = win.navigator.userAgent + &quot;;Ubiquity-share-on-delicious&quot;;

        req.setRequestHeader(&quot;User-Agent&quot;, user_agent);      

        req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        req.send(this._buildQueryString(bm));
    },

    EOF:null // I hate trailing commas
});
&lt;/pre&gt;


&lt;p&gt;The login cookie authentication supported by the Delicious V1 API is triggered by supplying a user name / password pair of &lt;code&gt;cookie&lt;/code&gt;, which is done by setting the &lt;code&gt;Authorization&lt;/code&gt; request header.  The login cookie is then expected to be passed in as the POST variable &lt;code&gt;_user&lt;/code&gt;, which is done in the &lt;code&gt;._extractBookmarkData()&lt;/code&gt; utility method.&lt;/p&gt;

&lt;p&gt;Another bit here that shows more access of browser resources is the construction of a unique User-Agent header for this API call based on the browser's own User-Agent string, something that's suggested in the guidelines for using the Delicious API.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;.execute()&lt;/code&gt; method—and the command itself—is wrapped up with by sending off the bookmark data encoded as POST form variables with the &lt;code&gt;._buildQueryString()&lt;/code&gt; utility method.&lt;/p&gt;

&lt;p&gt;And, that's it—a command-driven Delicious browser extension in a little over 200 lines of code.  There's still more to be done to really make this thing full-featured, but I think this shows off the basic features of Ubiquity.  I'm hoping to dig in deeper and explore further, taking a look at running Greasemonkey-style code at &lt;a href=&quot;https://wiki.mozilla.org/Labs/Ubiquity/Ubiquity_0.1_Author_Tutorial#Running_on_page_load_and_startup&quot;&gt;browser startup and page load&lt;/a&gt;, as well as playing with some more browser chrome features.&lt;/p&gt;

&lt;div id=&quot;comments&quot; class=&quot;comments archived-comments&quot;&gt;
            &lt;h3&gt;Archived Comments&lt;/h3&gt;
            
        &lt;ul class=&quot;comments&quot;&gt;
            
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085986&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://jclark.org/weblog/&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=d0a9ab4b71ce193e98b7284ca257e327&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://jclark.org/weblog/&quot;&gt;Jason Clark&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085986&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-09-01T14:47:35&quot;&gt;2008-09-01T14:47:35&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;First off-  fantastic post.  Great to see a lengthy post here again, although I'm one to talk.  This is an excellent introduction to Ubiquity command development, and tres useful to boot.&lt;/p&gt;

&lt;p&gt;I'm wondering why you chose to construct and post the XMLHttpRequest manually instead of using jQuery, which is included with Ubiquity.  I don't know that there's any benefit other than some simplicity, but I took a crack at converting your code to use jQuery, which works nicely.  In the 'execute' function, replace everything after &quot;var url  = this._config.api_base + path;&quot; with this (hope code blocks work in comments):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
        var win = context.focusedWindow;
        var user_agent = win.navigator.userAgent + &quot;;Ubiquity-share-on-delicious&quot;;&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    jQuery.ajax({
      type: &quot;POST&quot;,
      url: url,
      data: this._buildQueryString(bm),
      username: &quot;cookie&quot;,
      password: &quot;cookie&quot;,
      beforeSend: function( req ) {
        req.setRequestHeader(&quot;User-Agent&quot;, user_agent); 
      },
      error: function() {
        displayMessage('ERROR: Bookmark &quot;' + bm.description + '&quot; ' + 
            ' NOT shared on delicious.com/' + user_name);
      },
      success: function() {
        displayMessage('Bookmark &quot;' + bm.description + '&quot; ' + 
            'shared at delicious.com/' + user_name);
      },
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Also, with both versions of the code, I'm seeing some unexpected behavior around authentication.  Assume I'm logged in to delicious, with &quot;stay logged in&quot; checked, and I restart my browser.  Trying to post with the command fails with a 401 unauthorized, even though I can see the cookie was sent (via Live HTTP Headers extension).  Going to delicious.com shows me logged in, and once I've viewed the site, the command works.  Except that now I can't reproduce; but I know it happened because I've got the headers.  At any rate, it is working nicely, but the previous failure is bugging me... feel like I'm overlooking something.  &lt;/p&gt;

&lt;p&gt;Thanks again for an awesome post.  Hope to see more of the same.&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085988&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=e799a79441c7543be48562403411cd13&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;Ryan Scott Scheel&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085988&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-09-01T15:07:01&quot;&gt;2008-09-01T15:07:01&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;You should be helping with the documentation, if you aren't already.  Very nice job with this article;&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085991&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://azarask.in&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=e4307f205d017ba76647806951e14bb0&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://azarask.in&quot;&gt;Aza Raskin&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085991&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-09-02T01:44:13&quot;&gt;2008-09-02T01:44:13&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Hi Leslie,&lt;/p&gt;

&lt;p&gt;This is a beautiful tutorial on writing a Ubiquity command. We'd love your help in making Ubiquity's documentation better (especially dev facing). You should totally link to this from the Ubiquity Wiki -- or even add the content in someway.&lt;/p&gt;

&lt;p&gt;Anyway, just wanted to say thanks.&lt;/p&gt;

&lt;p&gt;-- Aza&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085993&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.slackorama.com&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=15b474c86cd73c2d12c1d77af11c1d8a&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.slackorama.com&quot;&gt;seth&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085993&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-09-08T17:30:16&quot;&gt;2008-09-08T17:30:16&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Am I doing something wrong?  &lt;/p&gt;

&lt;p&gt;When I enter in &quot;sh this tagged tag1 tag2 entitled This is a title&quot; everything after the tagged is added as a tag. It's not seeing the entitled part.&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085994&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://spyced.blogspot.com/&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=849810634810c960e5e7c27fa54a0f5b&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://spyced.blogspot.com/&quot;&gt;http://spyced.blogspot.com/&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085994&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-09-15T19:12:58&quot;&gt;2008-09-15T19:12:58&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Did something break?  I'm getting a 404 accessing http://decafbad.com/hg/UbiquityCommands/file/tip/delicious.ubiq.js&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085995&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.decafbad.com&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=2377f34a68801b861c3e54e1301f0dce&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.decafbad.com&quot;&gt;l.m.orchard&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085995&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-09-15T23:07:42&quot;&gt;2008-09-15T23:07:42&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Yeah, looks like I had a small snafu with switching back from Lighttpd to Apache.  Left out a rewrite rule - doh!&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085996&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=357a20e8c56e69d6f9734d23ef9517e8&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;Tony&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085996&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-10-22T04:56:03&quot;&gt;2008-10-22T04:56:03&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Great article. This is replacing my delicious bookmarklet. Thanks!&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085997&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=31461076fcbce091ff822fc9ac31315d&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;dgtlchlk&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085997&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2009-04-14T01:06:57&quot;&gt;2009-04-14T01:06:57&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Great article and command.
Wish it worked correctly with the latest 0.1.8 release though. No matter what text you put in it adds everything as the notes. The tagged and entitled modifiers don't work.&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221085999&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.nolanhergert.com&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=957e24509baf770ba57ad306e20f201c&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.nolanhergert.com&quot;&gt;Nolan&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221085999&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2009-04-16T03:10:07&quot;&gt;2009-04-16T03:10:07&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;I second that comment. Delicious is actually saying the link given was &quot;chrome://browser/content/browser.xul&quot; and marking it as harmful inside delicious!&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221086002&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=3d056a5b07c384647fe0806b0dfc429e&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;Justin&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221086002&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2009-07-06T12:39:39&quot;&gt;2009-07-06T12:39:39&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Hi Leslie,&lt;/p&gt;

&lt;p&gt;Thanks for the delicious ubiquity command. Unfortunately, as one of the commenters above mentions, the tagged modifier doesn't seem to work. I'm using Ubiquity 0.5 pre and typing the phrase:&lt;/p&gt;

&lt;p&gt;share tagged foo&lt;/p&gt;

&lt;p&gt;Adds the bookmark to Delicious with the note text &quot;tagged foo&quot;&lt;/p&gt;

&lt;p&gt;Cheers, Justin&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221086004&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://ericscalf.com/stream&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=0775f9beff626496b86d7cb602e5f46f&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://ericscalf.com/stream&quot;&gt;Eric&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221086004&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2009-07-20T22:43:17&quot;&gt;2009-07-20T22:43:17&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Echoing others.. I'm using the latest ubiquity (err, next to latest.. 0.1.8?), and doing &quot;share-on-delicious this is a note tagged testing&quot; saves the link with notes &quot;this is a note tagged testing&quot; and no tags. :(  Then again, the other delicious command I've found (by someone else) is having the same issue.&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;/ul&gt;
    
        &lt;/div&gt;



</content>
    </entry>
    
    

    <entry>
        <title>delicious 2.0 legacy bookmarklet fix</title>
        <link href="http://decafbad.com/blog/2008/08/02/delicious-20-legacy-bookmarklet-fix"/>
        <updated>2008-08-02T22:34:28+00:00</updated>
        <id>http://decafbad.com/blog/2008/08/02/delicious-20-legacy-bookmarklet-fix</id>
        <content type="html">&lt;p&gt;As you've probably seen by now, &lt;a href=&quot;http://blog.delicious.com/blog/2008/07/oh-happy-day.html&quot;&gt;Delicious 2.0 has launched&lt;/a&gt;.  It's an all new design and the whole thing has been rewritten from the ground up.  Most of the gripes I've seem like general dislike of change—which actually attests to the gargantuan effort put forth to reimplement the original from scratch in a whole new language and architecture.&lt;/p&gt;

&lt;p&gt;That said, I found &lt;a href=&quot;http://twitter.com/lmorchard/statuses/875002291&quot;&gt;at least one little bug&lt;/a&gt; that stops my usual bookmarklet flow.  And, what's really annoying is that, it's probably a bug in code I wrote at one point.  As it turns out, the original URL parameters for the bookmark posting form don't seem to be accepted anymore, so legacy bookmarklets may be broken.  I swore I tested that, since I've got some personal investment in it.&lt;/p&gt;

&lt;p&gt;But, although I can't contribute code to the project anymore, I've at least still got &lt;a href=&quot;http://www.greasespot.net/&quot;&gt;Greasemonkey&lt;/a&gt;.  And, through &lt;a href=&quot;http://decafbad.com/2008/deliciouscom_legacy_book.user.js&quot;&gt;this quick &amp;amp; dirty user script&lt;/a&gt;, I'm back to using my legacy bookmarking bookmarklets.  In case you're interested, &lt;a href=&quot;javascript:u=%22USERNAME%22;q=location.href;e%20=%20%22%22%20+%20(window.getSelection%20?%20window.getSelection()%20:%20document.getSelection%20?%20document.getSelection()%20%20:%20document.selection.createRange().text);p=document.title;window.location.href=%22http://del.icio.us/%22+u+%22?jump=doclose&amp;amp;noui&amp;amp;tags=%22+encodeURIComponent(%22%s%22)+%22&amp;amp;url=%22+encodeURIComponent(q)+%22&amp;amp;description=%22+encodeURIComponent(p)+%20%20%22&amp;amp;extended=%22%20+%20encodeURIComponent('%22'+e+'%22').replace(/%20/g,%20%22+%22);&quot;&gt;here's my favorite Firefox keyword shortcut bookmarklet&lt;/a&gt;—just select some text, type the keyword in the URL bar with some tags, and hit return.&lt;/p&gt;

&lt;div id=&quot;comments&quot; class=&quot;comments archived-comments&quot;&gt;
            &lt;h3&gt;Archived Comments&lt;/h3&gt;
            
        &lt;ul class=&quot;comments&quot;&gt;
            
        &lt;li class=&quot;comment&quot; id=&quot;comment-221084822&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=4762519f72e7ada7f2050a77eedca0e5&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;Peter Beardsley&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221084822&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-08-03T13:52:14&quot;&gt;2008-08-03T13:52:14&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Just curious-- what language was del.icio.us originally implemented in, and what language was it re-implemented in for 2.0?&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221084825&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.decafbad.com&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=2377f34a68801b861c3e54e1301f0dce&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.decafbad.com&quot;&gt;l.m.orchard&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221084825&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2008-08-03T18:30:58&quot;&gt;2008-08-03T18:30:58&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;@peter: The original del.icio.us was built with Mason in Perl, backed by MySQL.  The new Delicious 2 is built with Symfony in PHP for the web frontend, with all the out-of-box Symfony database abstraction replaced by a Yahoo!-developed data management and business logic layer written mostly in C++ for the backend.  I'm pretty sure I've read all of that in other public releases, so I don't think I'm letting any cats out of bags there :)&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;/ul&gt;
    
        &lt;/div&gt;



</content>
    </entry>
    
    

    <entry>
        <title>I can't get too ticked at O'Reilly and IntelliTXT</title>
        <link href="http://decafbad.com/blog/2006/01/14/i-cant-get-too-ticked-at-oreilly-and-intellitxt"/>
        <updated>2006-01-14T02:00:47+00:00</updated>
        <id>http://decafbad.com/blog/2006/01/14/i-cant-get-too-ticked-at-oreilly-and-intellitxt</id>
        <content type="html">&lt;p&gt;You know what I've been annoyed by lately?  Those contextual ads masquerading as &lt;a href=&quot;http://www.onlamp.com/pub/a/onlamp/2006/01/12/no_oss_community.html?page=1&quot; style=&quot;border-bottom: 3px double green&quot;&gt;double underlined links&lt;/a&gt; in the middle of the page.  Aren't these uncomfortably like &lt;a href=&quot;http://www.alistapart.com/articles/smarttags/&quot;&gt;Microsoft's Smart Tags&lt;/a&gt;?  Eh, maybe not, since the site owners are &lt;a href=&quot;http://www.oreillynet.com/pub/a/general/intellitxt.html&quot;&gt;willing collaborators&lt;/a&gt;—which makes it more of a successful service than a monopolist's sinister plan.&lt;/p&gt;

&lt;p&gt;On the other hand, in the midst of writing this little rant, I noticed that they provide &lt;a href=&quot;http://www.oreillynet.com/pub/a/general/intellitxt.html&quot;&gt;a mildly hidden opt-out&lt;/a&gt; at the bottom of the FAQ page.  Bah.  It's annoying, but at least there's that.&lt;/p&gt;

&lt;p&gt;And, well, folks gotta make money somehow I guess.  &lt;a href=&quot;http://www.oreillynet.com/pub/a/general/intellitxt.html&quot;&gt;The FAQ page&lt;/a&gt; is very honest about it:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;As we're sure many will appreciate, there is pressure for us to generate revenue from advertising to cover all of the costs, and this is an opportunity for us to do just that.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;So, other than the poor user experience of the popup layer when I accidentally roll my mouse over the wrong thing--I can't say they're being crass about it.&lt;/p&gt;

&lt;p&gt;Nonetheless: How long until I get itchy enough to make an anti-IntelliTXT Greasemonkey script, I wonder?&lt;/p&gt;

&lt;!-- tags: oreilly intellitxt advertising smarttags greasemonkey --&gt;




&lt;div id=&quot;comments&quot; class=&quot;comments archived-comments&quot;&gt;
            &lt;h3&gt;Archived Comments&lt;/h3&gt;
            
        &lt;ul class=&quot;comments&quot;&gt;
            
        &lt;li class=&quot;comment&quot; id=&quot;comment-221086038&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.lostfocus.de/&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=9e1f36d2a869f4ab38f107ea8aa94899&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.lostfocus.de/&quot;&gt;Dominik Schwind&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221086038&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2006-01-14T11:29:31&quot;&gt;2006-01-14T11:29:31&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;I found this one: http://dev.upian.com/hotlinks/archives/2005/09/29/#item44519 it seems to be working fine.&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221086043&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://jclark.org/weblog/&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=d0a9ab4b71ce193e98b7284ca257e327&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://jclark.org/weblog/&quot;&gt;Jason Clark&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221086043&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2006-01-14T15:56:26&quot;&gt;2006-01-14T15:56:26&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Lazyweb has beaten you to the punch.  I use IntelliTXT Disabler, which I found at &lt;a href=&quot;http://userscripts.org/&quot; rel=&quot;nofollow&quot;&gt;userscripts.org&lt;/a&gt;, and which is also available &lt;a href=&quot;http://slashetc.net/code/&quot; rel=&quot;nofollow&quot;&gt;from the author&lt;/a&gt;.  It runs after the page loads, of course, so you see the links appear briefly and then disappear.  I've found it quite useful.&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221086044&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=d8333ea779e4c5403687c02b54ac7304&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;&quot;&gt;Justin&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221086044&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2006-01-14T16:06:53&quot;&gt;2006-01-14T16:06:53&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;Greasemonkey is overkill for something you can block with &lt;a href=&quot;http://kb.mozillazine.org/Security_Policies#Prevent_any_JavaScript_function.2Fmember_from_being_run.2Fread.2Fset&quot; rel=&quot;nofollow&quot;&gt;CAPS&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user_pref(&quot;capability.policy.default.Window.itxtInited&quot;, &quot;noAccess&quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221086046&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.netalive.org/swsu/&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=77cc97db252efaca4468562f5795f025&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.netalive.org/swsu/&quot;&gt;Henning Koch&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221086046&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2006-01-15T15:32:46&quot;&gt;2006-01-15T15:32:46&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;&lt;a href=&quot;http://www.netalive.org/swsu/archives/2005/03/marketing_for_a_1.html&quot; rel=&quot;nofollow&quot;&gt;Because being fooled by IntelliTXT camouflage makes me want to buy shit every single time.&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;li class=&quot;comment&quot; id=&quot;comment-221086048&quot;&gt;
            &lt;div class=&quot;meta&quot;&gt;
                &lt;div class=&quot;author&quot;&gt;
                    &lt;a class=&quot;avatar image&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.briandonovan.info/self-assembly/&quot;&gt;&lt;img src=&quot;http://www.gravatar.com/avatar.php?gravatar_id=7c90794b1832074d199884a8dbaec510&amp;amp;size=32&amp;amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png&quot;/&gt;&lt;/a&gt;
                    &lt;a class=&quot;avatar name&quot; rel=&quot;nofollow&quot; 
                       href=&quot;http://www.briandonovan.info/self-assembly/&quot;&gt;Brian Donovan&lt;/a&gt;
                &lt;/div&gt;
                &lt;a href=&quot;#comment-221086048&quot; class=&quot;permalink&quot;&gt;&lt;time datetime=&quot;2006-06-18T18:14:00&quot;&gt;2006-06-18T18:14:00&lt;/time&gt;&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;content&quot;&gt;&lt;p&gt;I'm subbed to your blog but just came across this entry while searching for other IntelliTXT-cleaning GM scripts to help me decide whether it would be worthwhile to tidy up mine and add it to userscripts.org:&lt;/p&gt;

&lt;p&gt;http://userscripts.com/scripts/show/4250&lt;/p&gt;

&lt;p&gt;The cleaning function in this one is triggered whenever a DOMNodeInserted event fires, so it catches the bogus links immediately after they're implanted.  At least for me, this means that I never see a singe IntelliTXT link on any afflicted site.&lt;/p&gt;

&lt;p&gt;I tracked down 2 other anti-IntelliTXT user scripts but, while they each work, they both use setTimeout() to trigger their IntelliTXT cleaning functions with the result that you inevitably end up seeing the double-underlined pseudolinks for a moment or two before they're nuked.&lt;/p&gt;&lt;/div&gt;
            
        &lt;/li&gt;
    
        &lt;/ul&gt;
    
        &lt;/div&gt;



</content>
    </entry>
    
    
</feed>

