text: !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.githubFileBrowser=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
  var queue = _dereq_('queue-async'),
      request = _dereq_('browser-request'),
      treeui = _dereq_('treeui'),
      token;
  
  var base = 'https://api.github.com';
  
  var create = false;
  
  module.exports = function(_, _create,endpoint) {
      token = _;
      if (_create !== undefined) create = _create;
      base = endpoint || base;
      return module.exports;
  };
  
  module.exports.open = open;
  module.exports.request = req;
  
  function open() {
  
      var out = treeui(treeRequest)
          .expandable(function(res) {
              var last = res[res.length - 1];
              return last.type !== 'blob' && last.type !== 'commit' &&
                  last.type !== 'new';
          })
          .display(function(res) {
              var last = res[res.length - 1];
              return last.name || last.login || last.path;
          });
  
      return out;
  }
  
  function treeRequest(tree, callback) {
      if (tree.length === 0) {
          req('/user', function(err, user) {
              req('/user/orgs', function(err, res) {
                  var orgs = res.map(function(_) {
                      return [_];
                  });
                  callback(null, [user].concat(orgs));
              });
          });
      } else if (tree.length === 1) {
          if (tree[0].type === 'User') {
              req('/users/' + tree[0].login + '/repos', function(err, res) {
                  callback(null, res.map(function(_) {
                      return [tree[0], _];
                  }));
              });
          } else {
              req('/orgs/' + tree[0].login + '/repos', function(err, res) {
                  callback(null, res.map(function(_) {
                      return [tree[0], _];
                  }));
              });
          }
      } else if (tree.length === 2) {
          req('/repos/' + tree[1].full_name + '/branches', function(err, res) {
              callback(null, res.map(function(_) {
                  return [tree[0], tree[1], _];
              }));
          });
      } else if (tree.length === 3) {
          req('/repos/' + tree[1].full_name + '/git/trees/' + tree[2].commit.sha, function(err, res) {
              var r = [];
              if (!res.length && res.tree) res = [res];
              for (var i = 0; i < res.length; i++) {
                  for (var j = 0; j < res[i].tree.length; j++) {
                      r.push([tree[0], tree[1], tree[2], res[i].tree[j]]);
                  }
              }
              if (create) {
                  r.push([tree[0], tree[1], tree[2], {
                      type: 'new',
                      name: '+ New File'
                  }]);
              }
              callback(null, r);
          });
      } else if (tree.length > 3) {
          req('/repos/' + tree[1].full_name + '/git/trees/' + tree[tree.length - 1].sha, function(err, res) {
              var r = [];
              if (!res.length && res.tree) res = [res];
              for (var i = 0; i < res.length; i++) {
                  for (var j = 0; j < res[i].tree.length; j++) {
                      r.push(tree.concat([res[i].tree[j]]));
                  }
              }
              if (create) {
                  r.push([tree[0], tree[1], tree[2], {
                      type: 'new',
                      name: '+ New File'
                  }]);
              }
              callback(null, r);
          });
      }
  }
  
  function req(postfix, callback) {
      var q = queue(1);
      q.defer(page, null)
          .awaitAll(function(err, res) {
              if (res) {
                  var flat = res.reduce(function(mem, r) {
                      return mem.concat(r);
                  }, []);
                  callback(err, flat);
              } else {
                  callback(err);
              }
          });
  
      function page(url, callback) {
          request({
              uri: url || base + postfix,
              headers: {
                  Authorization: 'token ' + token
              },
              json: true,
              crossOrigin: true
          }, function(err, res, body) {
              var link = (res.getResponseHeader('Link') || '').match(/\<([^\>]+)\>\; rel="next"/);
              if (link) {
                  q.defer(page, link[1]);
              }
              callback(null, body);
          });
      }
  }
  
  },{"browser-request":2,"queue-async":3,"treeui":4}],2:[function(_dereq_,module,exports){
  // Browser Request
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  // UMD HEADER START 
  (function (root, factory) {
      if (typeof define === 'function' && define.amd) {
          // AMD. Register as an anonymous module.
          define([], factory);
      } else if (typeof exports === 'object') {
          // Node. Does not work with strict CommonJS, but
          // only CommonJS-like enviroments that support module.exports,
          // like Node.
          module.exports = factory();
      } else {
          // Browser globals (root is window)
          root.returnExports = factory();
    }
  }(this, function () {
  // UMD HEADER END
  
  var XHR = XMLHttpRequest
  if (!XHR) throw new Error('missing XMLHttpRequest')
  request.log = {
    'trace': noop, 'debug': noop, 'info': noop, 'warn': noop, 'error': noop
  }
  
  var DEFAULT_TIMEOUT = 3 * 60 * 1000 // 3 minutes
  
  //
  // request
  //
  
  function request(options, callback) {
    // The entry-point to the API: prep the options object and pass the real work to run_xhr.
    if(typeof callback !== 'function')
      throw new Error('Bad callback given: ' + callback)
  
    if(!options)
      throw new Error('No options given')
  
    var options_onResponse = options.onResponse; // Save this for later.
  
    if(typeof options === 'string')
      options = {'uri':options};
    else
      options = JSON.parse(JSON.stringify(options)); // Use a duplicate for mutating.
  
    options.onResponse = options_onResponse // And put it back.
  
    if (options.verbose) request.log = getLogger();
  
    if(options.url) {
      options.uri = options.url;
      delete options.url;
    }
  
    if(!options.uri && options.uri !== "")
      throw new Error("options.uri is a required argument");
  
    if(typeof options.uri != "string")
      throw new Error("options.uri must be a string");
  
    var unsupported_options = ['proxy', '_redirectsFollowed', 'maxRedirects', 'followRedirect']
    for (var i = 0; i < unsupported_options.length; i++)
      if(options[ unsupported_options[i] ])
        throw new Error("options." + unsupported_options[i] + " is not supported")
  
    options.callback = callback
    options.method = options.method || 'GET';
    options.headers = options.headers || {};
    options.body    = options.body || null
    options.timeout = options.timeout || request.DEFAULT_TIMEOUT
  
    if(options.headers.host)
      throw new Error("Options.headers.host is not supported");
  
    if(options.json) {
      options.headers.accept = options.headers.accept || 'application/json'
      if(options.method !== 'GET')
        options.headers['content-type'] = 'application/json'
  
      if(typeof options.json !== 'boolean')
        options.body = JSON.stringify(options.json)
      else if(typeof options.body !== 'string')
        options.body = JSON.stringify(options.body)
    }
    
    //BEGIN QS Hack
    var serialize = function(obj) {
      var str = [];
      for(var p in obj)
        if (obj.hasOwnProperty(p)) {
          str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        }
      return str.join("&");
    }
    
    if(options.qs){
      var qs = (typeof options.qs == 'string')? options.qs : serialize(options.qs);
      if(options.uri.indexOf('?') !== -1){ //no get params
          options.uri = options.uri+'&'+qs;
      }else{ //existing get params
          options.uri = options.uri+'?'+qs;
      }
    }
    //END QS Hack
    
    //BEGIN FORM Hack
    var multipart = function(obj) {
      //todo: support file type (useful?)
      var result = {};
      result.boundry = '-------------------------------'+Math.floor(Math.random()*1000000000);
      var lines = [];
      for(var p in obj){
          if (obj.hasOwnProperty(p)) {
              lines.push(
                  '--'+result.boundry+"\n"+
                  'Content-Disposition: form-data; name="'+p+'"'+"\n"+
                  "\n"+
                  obj[p]+"\n"
              );
          }
      }
      lines.push( '--'+result.boundry+'--' );
      result.body = lines.join('');
      result.length = result.body.length;
      result.type = 'multipart/form-data; boundary='+result.boundry;
      return result;
    }
    
    if(options.form){
      if(typeof options.form == 'string') throw('form name unsupported');
      if(options.method === 'POST'){
          var encoding = (options.encoding || 'application/x-www-form-urlencoded').toLowerCase();
          options.headers['content-type'] = encoding;
          switch(encoding){
              case 'application/x-www-form-urlencoded':
                  options.body = serialize(options.form).replace(/%20/g, "+");
                  break;
              case 'multipart/form-data':
                  var multi = multipart(options.form);
                  //options.headers['content-length'] = multi.length;
                  options.body = multi.body;
                  options.headers['content-type'] = multi.type;
                  break;
              default : throw new Error('unsupported encoding:'+encoding);
          }
      }
    }
    //END FORM Hack
  
    // If onResponse is boolean true, call back immediately when the response is known,
    // not when the full request is complete.
    options.onResponse = options.onResponse || noop
    if(options.onResponse === true) {
      options.onResponse = callback
      options.callback = noop
    }
  
    // XXX Browsers do not like this.
    //if(options.body)
    //  options.headers['content-length'] = options.body.length;
  
    // HTTP basic authentication
    if(!options.headers.authorization && options.auth)
      options.headers.authorization = 'Basic ' + b64_enc(options.auth.username + ':' + options.auth.password);
  
    return run_xhr(options)
  }
  
  var req_seq = 0
  function run_xhr(options) {
    var xhr = new XHR
      , timed_out = false
      , is_cors = is_crossDomain(options.uri)
      , supports_cors = ('withCredentials' in xhr)
  
    req_seq += 1
    xhr.seq_id = req_seq
    xhr.id = req_seq + ': ' + options.method + ' ' + options.uri
    xhr._id = xhr.id // I know I will type "_id" from habit all the time.
  
    if(is_cors && !supports_cors) {
      var cors_err = new Error('Browser does not support cross-origin request: ' + options.uri)
      cors_err.cors = 'unsupported'
      return options.callback(cors_err, xhr)
    }
  
    xhr.timeoutTimer = setTimeout(too_late, options.timeout)
    function too_late() {
      timed_out = true
      var er = new Error('ETIMEDOUT')
      er.code = 'ETIMEDOUT'
      er.duration = options.timeout
  
      request.log.error('Timeout', { 'id':xhr._id, 'milliseconds':options.timeout })
      return options.callback(er, xhr)
    }
  
    // Some states can be skipped over, so remember what is still incomplete.
    var did = {'response':false, 'loading':false, 'end':false}
  
    xhr.onreadystatechange = on_state_change
    xhr.open(options.method, options.uri, true) // asynchronous
    if(is_cors)
      xhr.withCredentials = !! options.withCredentials
    xhr.send(options.body)
    return xhr
  
    function on_state_change(event) {
      if(timed_out)
        return request.log.debug('Ignoring timed out state change', {'state':xhr.readyState, 'id':xhr.id})
  
      request.log.debug('State change', {'state':xhr.readyState, 'id':xhr.id, 'timed_out':timed_out})
  
      if(xhr.readyState === XHR.OPENED) {
        request.log.debug('Request started', {'id':xhr.id})
        for (var key in options.headers)
          xhr.setRequestHeader(key, options.headers[key])
      }
  
      else if(xhr.readyState === XHR.HEADERS_RECEIVED)
        on_response()
  
      else if(xhr.readyState === XHR.LOADING) {
        on_response()
        on_loading()
      }
  
      else if(xhr.readyState === XHR.DONE) {
        on_response()
        on_loading()
        on_end()
      }
    }
  
    function on_response() {
      if(did.response)
        return
  
      did.response = true
      request.log.debug('Got response', {'id':xhr.id, 'status':xhr.status})
      clearTimeout(xhr.timeoutTimer)
      xhr.statusCode = xhr.status // Node request compatibility
  
      // Detect failed CORS requests.
      if(is_cors && xhr.statusCode == 0) {
        var cors_err = new Error('CORS request rejected: ' + options.uri)
        cors_err.cors = 'rejected'
  
        // Do not process this request further.
        did.loading = true
        did.end = true
  
        return options.callback(cors_err, xhr)
      }
  
      options.onResponse(null, xhr)
    }
  
    function on_loading() {
      if(did.loading)
        return
  
      did.loading = true
      request.log.debug('Response body loading', {'id':xhr.id})
      // TODO: Maybe simulate "data" events by watching xhr.responseText
    }
  
    function on_end() {
      if(did.end)
        return
  
      did.end = true
      request.log.debug('Request done', {'id':xhr.id})
  
      xhr.body = xhr.responseText
      if(options.json) {
        try        { xhr.body = JSON.parse(xhr.responseText) }
        catch (er) { return options.callback(er, xhr)        }
      }
  
      options.callback(null, xhr, xhr.body)
    }
  
  } // request
  
  request.withCredentials = false;
  request.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
  
  //
  // defaults
  //
  
  request.defaults = function(options, requester) {
    var def = function (method) {
      var d = function (params, callback) {
        if(typeof params === 'string')
          params = {'uri': params};
        else {
          params = JSON.parse(JSON.stringify(params));
        }
        for (var i in options) {
          if (params[i] === undefined) params[i] = options[i]
        }
        return method(params, callback)
      }
      return d
    }
    var de = def(request)
    de.get = def(request.get)
    de.post = def(request.post)
    de.put = def(request.put)
    de.head = def(request.head)
    return de
  }
  
  //
  // HTTP method shortcuts
  //
  
  var shortcuts = [ 'get', 'put', 'post', 'head' ];
  shortcuts.forEach(function(shortcut) {
    var method = shortcut.toUpperCase();
    var func   = shortcut.toLowerCase();
  
    request[func] = function(opts) {
      if(typeof opts === 'string')
        opts = {'method':method, 'uri':opts};
      else {
        opts = JSON.parse(JSON.stringify(opts));
        opts.method = method;
      }
  
      var args = [opts].concat(Array.prototype.slice.apply(arguments, [1]));
      return request.apply(this, args);
    }
  })
  
  //
  // CouchDB shortcut
  //
  
  request.couch = function(options, callback) {
    if(typeof options === 'string')
      options = {'uri':options}
  
    // Just use the request API to do JSON.
    options.json = true
    if(options.body)
      options.json = options.body
    delete options.body
  
    callback = callback || noop
  
    var xhr = request(options, couch_handler)
    return xhr
  
    function couch_handler(er, resp, body) {
      if(er)
        return callback(er, resp, body)
  
      if((resp.statusCode < 200 || resp.statusCode > 299) && body.error) {
        // The body is a Couch JSON object indicating the error.
        er = new Error('CouchDB error: ' + (body.error.reason || body.error.error))
        for (var key in body)
          er[key] = body[key]
        return callback(er, resp, body);
      }
  
      return callback(er, resp, body);
    }
  }
  
  //
  // Utility
  //
  
  function noop() {}
  
  function getLogger() {
    var logger = {}
      , levels = ['trace', 'debug', 'info', 'warn', 'error']
      , level, i
  
    for(i = 0; i < levels.length; i++) {
      level = levels[i]
  
      logger[level] = noop
      if(typeof console !== 'undefined' && console && console[level])
        logger[level] = formatted(console, level)
    }
  
    return logger
  }
  
  function formatted(obj, method) {
    return formatted_logger
  
    function formatted_logger(str, context) {
      if(typeof context === 'object')
        str += ' ' + JSON.stringify(context)
  
      return obj[method].call(obj, str)
    }
  }
  
  // Return whether a URL is a cross-domain request.
  function is_crossDomain(url) {
    var rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/
  
    // jQuery #8138, IE may throw an exception when accessing
    // a field from window.location if document.domain has been set
    var ajaxLocation
    try { ajaxLocation = location.href }
    catch (e) {
      // Use the href attribute of an A element since IE will modify it given document.location
      ajaxLocation = document.createElement( "a" );
      ajaxLocation.href = "";
      ajaxLocation = ajaxLocation.href;
    }
  
    var ajaxLocParts = rurl.exec(ajaxLocation.toLowerCase()) || []
      , parts = rurl.exec(url.toLowerCase() )
  
    var result = !!(
      parts &&
      (  parts[1] != ajaxLocParts[1]
      || parts[2] != ajaxLocParts[2]
      || (parts[3] || (parts[1] === "http:" ? 80 : 443)) != (ajaxLocParts[3] || (ajaxLocParts[1] === "http:" ? 80 : 443))
      )
    )
  
    //console.debug('is_crossDomain('+url+') -> ' + result)
    return result
  }
  
  // MIT License from http://phpjs.org/functions/base64_encode:358
  function b64_enc (data) {
      // Encodes string using MIME base64 algorithm
      var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
      var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc="", tmp_arr = [];
  
      if (!data) {
          return data;
      }
  
      // assume utf8 data
      // data = this.utf8_encode(data+'');
  
      do { // pack three octets into four hexets
          o1 = data.charCodeAt(i++);
          o2 = data.charCodeAt(i++);
          o3 = data.charCodeAt(i++);
  
          bits = o1<<16 | o2<<8 | o3;
  
          h1 = bits>>18 & 0x3f;
          h2 = bits>>12 & 0x3f;
          h3 = bits>>6 & 0x3f;
          h4 = bits & 0x3f;
  
          // use hexets to index into b64, and append result to encoded string
          tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
      } while (i < data.length);
  
      enc = tmp_arr.join('');
  
      switch (data.length % 3) {
          case 1:
              enc = enc.slice(0, -2) + '==';
          break;
          case 2:
              enc = enc.slice(0, -1) + '=';
          break;
      }
  
      return enc;
  }
      return request;
  //UMD FOOTER START
  }));
  //UMD FOOTER END
  
  },{}],3:[function(_dereq_,module,exports){
  (function() {
    var slice = [].slice;
  
    function queue(parallelism) {
      var q,
          tasks = [],
          started = 0, // number of tasks that have been started (and perhaps finished)
          active = 0, // number of tasks currently being executed (started but not finished)
          remaining = 0, // number of tasks not yet finished
          popping, // inside a synchronous task callback?
          error = null,
          await = noop,
          all;
  
      if (!parallelism) parallelism = Infinity;
  
      function pop() {
        while (popping = started < tasks.length && active < parallelism) {
          var i = started++,
              t = tasks[i],
              a = slice.call(t, 1);
          a.push(callback(i));
          ++active;
          t[0].apply(null, a);
        }
      }
  
      function callback(i) {
        return function(e, r) {
          --active;
          if (error != null) return;
          if (e != null) {
            error = e; // ignore new tasks and squelch active callbacks
            started = remaining = NaN; // stop queued tasks from starting
            notify();
          } else {
            tasks[i] = r;
            if (--remaining) popping || pop();
            else notify();
          }
        };
      }
  
      function notify() {
        if (error != null) await(error);
        else if (all) await(error, tasks);
        else await.apply(null, [error].concat(tasks));
      }
  
      return q = {
        defer: function() {
          if (!error) {
            tasks.push(arguments);
            ++remaining;
            pop();
          }
          return q;
        },
        await: function(f) {
          await = f;
          all = false;
          if (!remaining) notify();
          return q;
        },
        awaitAll: function(f) {
          await = f;
          all = true;
          if (!remaining) notify();
          return q;
        }
      };
    }
  
    function noop() {}
  
    queue.version = "1.0.7";
    if (typeof define === "function" && define.amd) define(function() { return queue; });
    else if (typeof module === "object" && module.exports) module.exports = queue;
    else this.queue = queue;
  })();
  
  },{}],4:[function(_dereq_,module,exports){
  module.exports = function(request) {
      var parent = ce('div', 'treeui'),
          onclick = function() { };
  
      var addItem = function(result) {
          var item = ce('div', 'treeui-item');
          item.level = JSON.stringify(result);
  
          if (expandable(result)) {
              var caret = append(item, ce('span', 'treeui-caret'));
              caret.innerHTML = '▶';
              caret.level = JSON.stringify(result);
              ae(caret, 'click', toggle);
          }
  
          var description = append(item, ce('span', 'treeui-label'));
          description.innerHTML = display(result);
  
          ae(description, 'click', function(e) {
              onclick(JSON.parse(e.target.parentNode.level), e);
          });
  
          return item;
      };
  
      var display = function(result) {
          return result;
      };
  
      var expandable = function(result) {
          return true;
      };
  
      function toggle(e) {
          var elem = e.target,
              parent = e.target.parentNode;
          if (elem.classList.contains('open')) {
              var subs = parent.getElementsByClassName('treeui-level');
              for (var i = 0; i < subs.length; i++) {
                  subs[i].parentNode.removeChild(subs[i]);
              }
              elem.classList.remove('open');
              elem.innerHTML = '▶';
          } else {
              load(JSON.parse(parent.level),
                   append(parent, ce('div', 'treeui-level')));
              elem.classList.add('open');
              elem.innerHTML = '▼';
          }
      }
  
      function load(level, parent) {
          request(level, function(err, results) {
              if (err) return;
              results.forEach(function(result) {
                  append(parent, addItem(result));
              });
          });
      }
  
      load([], parent);
  
      var treeui = {
          appendTo: function(elem) {
              elem.appendChild(parent);
              return treeui;
          },
          onclick: function(_) {
              onclick = _;
              return treeui;
          },
          display: function(_) {
              display = _;
              return treeui;
          },
          expandable: function(_) {
              expandable = _;
              return treeui;
          }
      };
  
      return treeui;
  };
  
  function ce(_, k) {
      var elem = document.createElement(_);
      if (k) elem.className = k;
      return elem;
  }
  
  function append(x, y) {
      return x.appendChild(y);
  }
  
  function ae(x, y, z) {
      return x.addEventListener(y, z);
  }
  
  },{}]},{},[1])
  (1)
  });