String.prototype.endsWith = function(str) {
    return (this.length-str.length)==this.lastIndexOf(str);
}

String.prototype.startsWith = function(str) {
    return this.substring(0, str.length) == str;
}

Array.prototype.exists = function (x) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] == x) return true;
    }
    return false;
}

function rUrl(url) {
  var r = new Date().getTime();var h = "http://";
  if (url.substring(0, h.length).toLowerCase() == h) h = "";
  return h+url+((url.indexOf('?') == -1)?'?r':'&r')+r+'='+r;
}

function ScriptLoader() {
  this.loaded = [];

  this.loadCSS = function (url, urls, callback) {
    if(document.createStyleSheet) {
      document.createStyleSheet(url);
    } else {
      var styles = "@import url("+rUrl(url)+");";
      var newSS=document.createElement('link');
      newSS.rel='stylesheet';
      newSS.href='data:text/css,'+escape(styles);
      document.getElementsByTagName("head")[0].appendChild(newSS);
    }
    // TODO: Determine whether we need to wait for the CSS to load here. onload() doesn't
    //       exist for css elements.
    this.load(urls, callback);
  }

  this.reloadCSS = function (url, urls, callback) {
    var i,a,s;
    a=document.getElementsByTagName('link');
    for(i=0;i<a.length;i++){
      s = a[i];
      if ((s.rel.toLowerCase().indexOf('stylesheet') >= 0) && s.href && s.href.indexOf() ) {
        s.href = rUrl(s.href.replace(/(&|\?)r\d+=\d+/, ''));
      }
    }
  }
  this.loadJS = function(url, urls, callback) {
     var h = document.getElementsByTagName("head")[0];
     var s = document.createElement("script");
     s.src = rUrl(url);
     var done = false;
     var t = this;
     s.onload = s.onreadystatechange = function() {
       var rs = this.readyState;
       if( !done && ( !rs || rs == "loaded" || rs == "complete") ) {
         done = true;
         if (urls.length > 0) {
           t.load(urls, callback);
         } else {
           // Really, I'm not sure of the value of this. Basically, by using an
           // additional javascript file you get the advantage of dividing up
           // your code, caching this file, and not having specific code
           // polluting your bookmarklet. *shrug* We'll see how it goes.
           if (callback)
              callback();
         }
         s.onload = s.onreadystatechange = null;
         h.removeChild( s );
       }
       }
     h.appendChild(s);
  }

  this.load = function(urls, callback) {
     var url = null;
     while (urls.length > 0) {
       url = urls.shift();
       if (this.loaded.exists(url) && (!url.toLowerCase().endsWith(".css"))) {
          continue;
       }
       if (urls.length > 0) {
          this.loaded.push(url);
          break;
       }
       break;
     }

     if (url.toLowerCase().endsWith(".css")) {
        this.loadCSS(url, urls, callback);
     } else this.loadJS(url, urls, callback);

    }
}

if (typeof urls == "object") {
   if (typeof scriptLoader == 'undefined')
      scriptLoader = new ScriptLoader();
   if (typeof callback != 'undefined') {
       scriptLoader.load(urls,callback);
     } else { scriptLoader.load(urls); }
} else {
   alert('No URLS were specified. Bookmarklet likely built wrong!');
}


