    //
    // As mentioned at http://en.wikipedia.org/wiki/XMLHttpRequest
    //
    if( !window.XMLHttpRequest ) XMLHttpRequest = function()
    {
      try{ return new ActiveXObject("Msxml2.XMLHTTP.6.0") }catch(e){}
      try{ return new ActiveXObject("Msxml2.XMLHTTP.3.0") }catch(e){}
      try{ return new ActiveXObject("Msxml2.XMLHTTP") }catch(e){}
      try{ return new ActiveXObject("Microsoft.XMLHTTP") }catch(e){}
      throw new Error("Could not find an XMLHttpRequest alternative.")
    };

    //
    // Makes an AJAX request to a local server function w/ optional arguments
    //
    // functionName: the name of the server's AJAX function to call
    // opt_argv: an Array of arguments for the AJAX function
    //

function Request(function_name, opt_argv) {

  if (!opt_argv)
    opt_argv = new Array();

  // Find if the last arg is a callback function; save it
  var callback = null;
  var len = opt_argv.length;
  if (len > 0 && typeof opt_argv[len-1] == 'function') {
    callback = opt_argv[len-1];
    opt_argv.length--;
  }
  var async = (callback != null);

  // Build an Array of parameters, w/ function_name being the first parameter
  var params = new Array(function_name);
  for (var i = 0; i < opt_argv.length; i++) {
    params.push(opt_argv[i]);
  }
  var body = JSON.stringify(params);

  // Create an XMLHttpRequest 'POST' request w/ an optional callback handler
  var req = new XMLHttpRequest();
  req.open('POST', '/rpc', async);

  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  //req.setRequestHeader("Content-length", body.length);
  //req.setRequestHeader("Connection", "close");

  if (async) {
    req.onreadystatechange = function() {
      if(req.readyState == 4 && req.status == 200) {
        var response = null;
        try {
         response = JSON.parse(req.responseText);
        } catch (e) {
         response = req.responseText;
        }
        callback(response);
      }
    }
  }

  // Make the actual request
  req.send(body);
    if (!async) {
	response = req.responseText;
    }
}

// Adds a stub function that will pass the arguments to the AJAX call
function InstallFunction(obj, functionName) {
    obj[functionName] = function() { Request(functionName, arguments); }
}

// Server object that will contain the callable methods
var server = {};

InstallFunction(server, 'PostComment');
InstallFunction(server, 'ToggleSubscribe');

// Handy "macro"
function $$(id){
    return document.getElementById(id);
}

// Ajax Functions


function doToggleSubscribe() {
    var nodekeyname = $("input[name=nodekeyname]").val()
    server.ToggleSubscribe(nodekeyname, onToggleSubscribeSuccess);
}

function onToggleSubscribeSuccess(response) {
    var result = response[0];
    var url = response[1];
    if (result == 0) {
	showMessage("You are now subscribed",false);
	$("a#subscribe_star").removeClass("unsub").addClass("sub").attr('title','Unsubscribe');
    } else if (result == 1) {
	showMessage("You are no longer subscribed",false);
	$("a#subscribe_star").removeClass("sub").addClass("unsub").attr('title','Subscribe');
    } else if (result == 2) {
	window.location = url;
    }
}

function doPostComment() {
    var comment = $("textarea[name=comment]").val();
    var key = $("input[name=key]").val();
    if (comment.length > 0) {
	$("textarea[name=comment]").attr("disabled",true);
	server.PostComment(key, comment, onPostCommentSuccess);    
    }
}

function onPostCommentSuccess(response) {
    var comment_html = response[0];
    $("textarea[name=comment]").attr("disabled",false).val("");
    $("#comments ul li#add").before("<li class='new'>"+comment_html+"</li>");
    borderFade($("#comments ul li.new #bubble"),"yellow","#DDD");
    colorFade($("#comments ul li.new .author"),"yellow","black");
    $("li.new").removeClass('new');
}

