Saturday, September 27, 2008

Strategy vs. Tactics: The first presidential debate


Chess is a battle; Go is a war.
In the first presidential debate last night, I think Obama made an excellent point about the difference between a strategy and a tactic. Perhaps it's sometimes hard to tell the difference; it's a matter of scope.
If you compare: invading Iraq verses the troop surge, then the invasion is the strategy and the troop surge is the tactic.
If you compare the troop surge verses force dispersal then the troop surge is a strategy and the force dispersal is a tactic.
Some might say that if you compare the games of chess and checkers, that checkers is the tactical game and chess is the strategic game.
Then again if you compare chess with the game of Go, you might think, as has been said many times, that "Chess is a battle and Go is a war."
Near the end of the debate, Obama made a huge point about strategy verses tactics, that the strength of our military is dependent on the strength of our economy.
Here's a very paraphrased version of what he said. I've trimmed for coherence in writing verses speaking I've cut out things that aren't relevant to my point. Since I've changed it so much, I won't even put quotes around it. See the transcript for exactly what Obama said:
China is active in regions like Latin America, and Asia, and Africa. The conspicuousness of their presence is only matched by our absence, because we've been focused on Iraq.
We have weakened our capacity to project power around the world because we have viewed everything through this single lens, not to mention, look at our economy. We are now spending $10 billion or more every month on Iraq.
There has never been a country on Earth that saw its economy decline and yet maintained its military superiority.
The troop surge might have turned out to be a fine tactic in the context of a bad strategy. It's penny wise, pound foolish. So it's not a matter of making the right moves, it's the game you choose to play. Obama is right about the strategy, and Obama is right about which table we're sitting at, who we are sitting across from, and about the size of the board and the shape of the pieces.

Tuesday, September 2, 2008

Does Google's Chrome help with Mashups?


Google's new web browser, Chrome sounds like it's been nicely designed with security in mind, but their announcement and cute comic book don't say anything about mashups security. There are some interesting browser-side approaches to making javascript mashups less scary. I hope they've considered mashups in the design of their separation system.

If anyone has pointers to this topic, let me know.

Monday, September 1, 2008

Drubiquity: a proof-of-concept Ubiquity interface for Drupal


I've been pretty impressed with Ubiquity, a Firefox extension that combines web APIs with the command-line and some natural language processing, so you can compose together applications using javascript in a very unix-y way.

As an experiment and a weekend hack, I wanted to create an interface to Drupal, the awesome software that I run my blog on. I have something pretty cool working, but sadly, I can't really recommend using it, because the REST API that I integrated with has some serious problems. Maybe I'll get around to re-implementing this with the Services API system, but it's late Sunday and I haven't gotten around to that yet, so I thought I'd post. Anyone is welcome to pick this up and make it work for real :)
Read on for a screenshot and the source code.

Right now, what my ubiquity command does is queries the API of a Drupal site for the list of users, and matches that list against what the user types. So if the user types "drubiquity ijones", they'll get two users on my site, me and a test user.

The preview function uses the API to fetch the picture of the user that you're currently looking at and insert it asynchronously, as shown below. Then if you hit "enter" it will bring you to the blog for that user.

It should be simple to extend for some more uses. For instance, you could implement something like the "twitter" command to post a brief blog entry for a Drupal site, or the preview function could list recent blog entries or more info about the user. Leaning more toward the mashup idea, you could map user locations, or insert photo album pictures into an email, or click on an image and blog about it, etc. The fun thing is that lots of sites use Drupal, so anything you build with Ubiquity can be leveraged across all those sites.

Here's a screenshot and the source code in case anyone is interested. I should warn you that I'm not exactly a Javascript programmer, so your mileage may vary. I'll post again if I end up re-implementing this with the services API.

// ------------------------------------------------------------
// * Site specific things to modify:
// ------------------------------------------------------------

//change the command to something about your site:
const cmdName = "drubiquity";

//If you modify this, you are the author:
const currentAuthor = { name: "Isaac Potoczny-Jones", email: "ijones@syntaxpolice.org"};

//Set this to your home page for documentation purposes.
const currentHomepage = "http://www.syntaxpolice.org/";

//This should point to the root of your drupal site:
const sourceURL = "http://www.syntaxpolice.org/index.php/";

// This should point to the root of your rest / JSON API. If it's
// correct, you should be able to go to jsonURLRoot/help and see
// instructions for what's available.  You must install this pluggin:
// http://drupal.org/project/restapi

const jsonURLRoot = sourceURL + "?q=/=/";

//end site-specific modifications


// Dynamically match input to the list of usernames
var noun_type_user = {
  _name: "user name",
  userList: null,

  callback: function (users) {
        noun_type_user.userList = users.value;
    },

  suggest: function( text, html ) {
        //fetch the list of users and suggest them.
            var jsonURL = jsonURLRoot + "user/name.json";
            if (noun_type_user.userList == null) {
                jQuery.getJSON(jsonURL, noun_type_user.callback);
                return [];
            }
            if (text.length < 2) return [];
            
            var suggestions = [];
            for ( i = 0; i < noun_type_user.userList.length; i++ ) {
                var userName = noun_type_user.userList[i];
                if (userName.match(text, "i") && userName != "" )
                    suggestions.push(CmdUtils.makeSugg(userName));
            }
            return suggestions.splice(0, 5);
  }
} //username type


CmdUtils.CreateCommand({
  name: cmdName,
  homepage: currentHomepage,
  author: currentAuthor,

  contributors: ["Isaac Potoczny-Jones"],
  license: "BSD3",
  description: "Some commands to interact with Drupal."
           + " Requires the Rest API extension on the target site.",
  help: "Type '" 
            + cmdName + "' and you should get some hints.  You can search for users "
            + "by typing a few letters of their username. You should be presented "
            + "with a preview picture if they have one on file. Hit enter for the "
            + "given user, and you'll be taken to their blog.",

  takes: { "user": noun_type_user},

  preview: function( pblock, userName ) {
            //displays user's image if available.
            var prevMessage = "View blog for user: " + userName.text;
            pblock.innerHTML = prevMessage;
 
            getUserRec (userName,
                        function(user){
                            var picURL =  sourceURL + user.value.picture;
                            pblock.innerHTML = ""
                                + prevMessage;
                        });
  },

  execute: function( userName ) {
            //looks up user's uid and constructs blog URL from that.
            getUserRec (userName,
                        function (user) {
                            var blogURL = sourceURL + "?q=blog/" + user.value.uid;
                            Utils.openUrlInBrowser (blogURL);
                        });
        }
})

// looks up the user record given the user name object. callback takes user record
function getUserRec (userName, userCallback ) {

    var userNameSt = userName.text;
    var jsonURL = jsonURLRoot + "user/name/" + userNameSt + ".json";
    var prevMessage = "View blog for user: " + userNameSt;
    
    jQuery.getJSON(jsonURL, 
                   function(user){
                       userCallback (user);
                   });
   
}