docs: function(uri, options, cb) {
  
          // arguments parsing
          var al = arguments.length;
          if (al === 3) {}
          else if (al === 2) {
              cb = options;
              options = {};
          }
          else {
              throw new TypeError('ajax expects arguments: ({String}uri, [{Object}options], {Function}cb');
          }
  
          if (!('method'     in options)) { options.method     = 'GET'; }
          if (!('parameters' in options)) { options.parameters = {};    }
          if (!('headers'    in options)) { options.headers    = {};    }
  
          // set parameters
          var hasQM = uri.lastIndexOf('?') !== -1;
          var k, v, p = [];
          for (k in options.parameters) {
              v = options.parameters[k];
              p.push( [k, encodeURIComponent(v)].join('=') );
          }
          p = p.join('&');
          uri = [uri, p].join(hasQM ? '&' : '?');
  
          // create comm object
          var xhr = new XMLHttpRequest();
          if ('withCredentials' in xhr) { // chrome/safari/ff/opera
              xhr.open(options.method, uri, true);
          }
          else if (XDomainRequest) { // ie 8+
              xhr = new XDomainRequest();
              xhr.open(options.method, uri);
          }
          else {
              return cb('unsupported browser');
          }
  
          // set headers
          for (k in options.headers) {
              v = options.headers[k];
              xhr.setRequestHeader(k, v);   
          }
  
          // setup callback to handle result
          var cbInner = function() {
              if (xhr.readyState === 4 && xhr.status === 200) {
                  return cb(null, JSON.parse(xhr.response));
              }
              cb('error requesting ' + uri);
          };
          xhr.onload  = cbInner;
          xhr.onerror = cbInner;
  
          // fire request
          xhr.send(null);
      }