// Generated by IcedCoffeeScript 1.8.0-d
(function() {
  var BaseScraper, BearerToken, Lock, TwitterScraper, bearer_token, constants, decode_sig, iced, make_ids, sncmp, urlmod, v_codes, ws_normalize, __iced_k, __iced_k_noop, _bearer_token, _ref,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  iced = require('iced-runtime');
  __iced_k = __iced_k_noop = function() {};

  _ref = require('./base'), sncmp = _ref.sncmp, BaseScraper = _ref.BaseScraper;

  make_ids = require('../base').make_ids;

  constants = require('../constants').constants;

  Lock = require('../util').Lock;

  v_codes = constants.v_codes;

  decode_sig = require('kbpgp').ukm.decode_sig;

  urlmod = require('url');

  ws_normalize = function(x) {
    var v;
    v = x.split(/[\t\r\n ]+/);
    if (v.length && v[0].length === 0) {
      v.shift();
    }
    if (v.length && v.slice(-1)[0].length === 0) {
      v.pop();
    }
    return v.join(' ');
  };

  BearerToken = (function() {
    function BearerToken(_arg) {
      this.base = _arg.base;
      this._tok = null;
      this._created = 0;
      this._lock = new Lock();
      this.auth = this.base.auth;
    }

    BearerToken.prototype.get = function(cb) {
      var body, cred, e, err, now, opts, rc, res, tok, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
            funcname: "BearerToken.get"
          });
          _this._lock.acquire(__iced_deferrals.defer({
            lineno: 31
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          err = null;
          now = Math.floor(Date.now() / 1000);
          (function(__iced_k) {
            if (((res = _this._tok) == null) || (now - _this._created > _this.auth.lifespan)) {
              _this.base.log("+ Request for bearer token");
              cred = (new Buffer([_this.auth.key, _this.auth.secret].join(":"))).toString('base64');
              opts = {
                url: "https://api.twitter.com/oauth2/token",
                headers: {
                  Authorization: "Basic " + cred
                },
                form: {
                  grant_type: "client_credentials"
                },
                method: "POST"
              };
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
                  funcname: "BearerToken.get"
                });
                _this.base._get_url_body(opts, __iced_deferrals.defer({
                  assign_fn: (function() {
                    return function() {
                      err = arguments[0];
                      rc = arguments[1];
                      return body = arguments[2];
                    };
                  })(),
                  lineno: 50
                }));
                __iced_deferrals._fulfill();
              })(function() {
                if (err != null) {
                  _this.base.logl('error', "In getting bearer_token: " + err.message);
                } else if (rc !== v_codes.OK) {
                  _this.base.logl('error', "HTTP error in getting bearer token: " + rc);
                  err = new Error("HTTP error: " + rc);
                } else {
                  try {
                    body = JSON.parse(body);
                  } catch (_error) {
                    e = _error;
                    _this.base.logl('warn', "Could not parse JSON reply: " + e);
                    err = e;
                  }
                }
                if (err != null) {

                } else if ((tok = body.access_token) == null) {
                  _this.base.logl('warn', "No access token found in reply");
                  err = new Error("Twitter error: no access token");
                } else {
                  _this._tok = tok;
                  _this._created = Math.floor(Date.now() / 1000);
                  res = _this._tok;
                }
                return __iced_k(_this.base.log("- Request for bearer token -> " + err));
              });
            } else {
              return __iced_k();
            }
          })(function() {
            _this._lock.release();
            return cb(err, res);
          });
        };
      })(this));
    };

    return BearerToken;

  })();

  _bearer_token = null;

  bearer_token = function(_arg) {
    var base;
    base = _arg.base;
    if (!_bearer_token) {
      _bearer_token = new BearerToken({
        base: base
      });
    }
    return _bearer_token;
  };

  exports.TwitterScraper = TwitterScraper = (function(_super) {
    __extends(TwitterScraper, _super);

    function TwitterScraper(opts) {
      this.auth = opts.auth;
      TwitterScraper.__super__.constructor.call(this, opts);
    }

    TwitterScraper.prototype._check_args = function(args) {
      if (!(args.username != null)) {
        return new Error("Bad args to Twitter proof: no username given");
      } else if (!(args.name != null) || (args.name !== 'twitter')) {
        return new Error("Bad args to Twitter proof: type is " + args.name);
      } else {
        return null;
      }
    };

    TwitterScraper.prototype.hunt2 = function(_arg, cb) {
      var api_url, err, human_url, i, id_str, json, name, out, proof_text_check, rc, remote_id, text, u, username, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      username = _arg.username, name = _arg.name, proof_text_check = _arg.proof_text_check;
      out = {};
      rc = v_codes.OK;
      if ((err = this._check_args({
        username: username,
        name: name
      })) != null) {
        return cb(err, out);
      }
      u = urlmod.format({
        host: "api.twitter.com",
        protocol: "https:",
        pathname: "/1.1/statuses/user_timeline.json",
        query: {
          count: 100,
          screen_name: username
        }
      });
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
            funcname: "TwitterScraper.hunt2"
          });
          _this._get_body_api({
            url: u
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                rc = arguments[1];
                return json = arguments[2];
              };
            })(),
            lineno: 122
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          var _i, _len, _ref1;
          _this.log("| search index " + u + " -> " + rc);
          if (rc !== v_codes.OK) {

          } else if ((typeof json === "undefined" || json === null) || (json.length === 0)) {
            rc = v_codes.EMPTY_JSON;
          } else {
            for (i = _i = 0, _len = json.length; _i < _len; i = ++_i) {
              _ref1 = json[i], text = _ref1.text, id_str = _ref1.id_str;
              if ((_this.find_sig_in_tweet({
                inside: text,
                proof_text_check: proof_text_check
              })) === v_codes.OK) {
                _this.log("| found valid tweet in stream @ " + i);
                rc = v_codes.OK;
                remote_id = id_str;
                api_url = human_url = _this._id_to_url(username, remote_id);
                out = {
                  remote_id: remote_id,
                  api_url: api_url,
                  human_url: human_url
                };
                break;
              }
            }
          }
          out.rc = rc;
          return cb(err, out);
        };
      })(this));
    };

    TwitterScraper.prototype.users_lookup = function(_arg, cb) {
      var batch_size, cursor_wait, dict, done, err, i, identifier, ids, include_entities, input_list, j, json, key, query, r, rc, res, responses, screen_names, u, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      ids = _arg.ids, screen_names = _arg.screen_names, cursor_wait = _arg.cursor_wait, include_entities = _arg.include_entities;
      if (ids && screen_names) {
        throw new Error('users_lookup cannot take ids and screen_names');
      }
      input_list = ids || screen_names;
      err = null;
      responses = [];
      cursor_wait = cursor_wait != null ? cursor_wait : 100;
      i = 0;
      include_entities = include_entities != null ? include_entities : false;
      batch_size = 100;
      done = false;
      (function(_this) {
        return (function(__iced_k) {
          var _results, _while;
          _results = [];
          _while = function(__iced_k) {
            var _break, _continue, _next;
            _break = function() {
              return __iced_k(_results);
            };
            _continue = function() {
              return iced.trampoline(function() {
                return _while(__iced_k);
              });
            };
            _next = function(__iced_next_arg) {
              _results.push(__iced_next_arg);
              return _continue();
            };
            if (!!done) {
              return _break();
            } else {
              j = Math.min(i + batch_size, input_list.length);
              query = {
                include_entities: include_entities
              };
              if (ids != null) {
                query.user_id = ids.slice(i, j).join(',');
              } else {
                query.screen_name = screen_names.slice(i, j).join(',');
              }
              u = urlmod.format({
                host: "api.twitter.com",
                protocol: "https:",
                pathname: "/1.1/users/lookup.json",
                query: query
              });
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
                  funcname: "TwitterScraper.users_lookup"
                });
                _this._get_body_api({
                  url: u
                }, __iced_deferrals.defer({
                  assign_fn: (function() {
                    return function() {
                      err = arguments[0];
                      rc = arguments[1];
                      return json = arguments[2];
                    };
                  })(),
                  lineno: 170
                }));
                __iced_deferrals._fulfill();
              })(function() {
                _this.log("| users_lookup " + i + "..." + j);
                (function(__iced_k) {
                  if (err != null) {
                    return __iced_k(done = true);
                  } else {
                    (function(__iced_k) {
                      if (rc !== v_codes.OK) {
                        err = new Error("failed to scrape; not ok " + rc);
                        return __iced_k(done = true);
                      } else {
                        (function(__iced_k) {
                          var _i, _len;
                          if (!(typeof json !== "undefined" && json !== null ? json.length : void 0)) {
                            err = new Error("failed to scrape; empty json " + v_codes.EMPTY_JSON);
                            return __iced_k(done = true);
                          } else {
                            for (_i = 0, _len = json.length; _i < _len; _i++) {
                              u = json[_i];
                              responses.push(u);
                            }
                            (function(__iced_k) {
                              if (j !== input_list.length) {
                                i = j;
                                (function(__iced_k) {
                                  __iced_deferrals = new iced.Deferrals(__iced_k, {
                                    parent: ___iced_passed_deferral,
                                    filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
                                    funcname: "TwitterScraper.users_lookup"
                                  });
                                  setTimeout(__iced_deferrals.defer({
                                    lineno: 184
                                  }), cursor_wait);
                                  __iced_deferrals._fulfill();
                                })(__iced_k);
                              } else {
                                return __iced_k(done = true);
                              }
                            })(function() {
                              return __iced_k(_this.log("| got " + json.length + " more; total=" + responses.length));
                            });
                          }
                        })(__iced_k);
                      }
                    })(__iced_k);
                  }
                })(_next);
              });
            }
          };
          _while(__iced_k);
        });
      })(this)((function(_this) {
        return function() {
          var _i, _j, _len, _len1;
          if (responses != null ? responses.length : void 0) {
            dict = {};
            key = ids != null ? "id_str" : "screen_name";
            for (_i = 0, _len = responses.length; _i < _len; _i++) {
              r = responses[_i];
              dict[r[key]] = r;
            }
            res = [];
            for (i = _j = 0, _len1 = input_list.length; _j < _len1; i = ++_j) {
              identifier = input_list[i];
              res[i] = dict[identifier] || null;
            }
          }
          return cb(err, res);
        };
      })(this));
    };

    TwitterScraper.prototype.get_follower_ids = function(_arg, cb) {
      var cursor, cursor_wait, done, err, friends, json, rc, res, stop_at, u, username, x, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      username = _arg.username, cursor_wait = _arg.cursor_wait, stop_at = _arg.stop_at, friends = _arg.friends;
      done = false;
      cursor = -1;
      err = null;
      res = [];
      cursor_wait = cursor_wait != null ? cursor_wait : 1000;
      stop_at = stop_at || Infinity;
      (function(_this) {
        return (function(__iced_k) {
          var _results, _while;
          _results = [];
          _while = function(__iced_k) {
            var _break, _continue, _next;
            _break = function() {
              return __iced_k(_results);
            };
            _continue = function() {
              return iced.trampoline(function() {
                return _while(__iced_k);
              });
            };
            _next = function(__iced_next_arg) {
              _results.push(__iced_next_arg);
              return _continue();
            };
            if (!!done) {
              return _break();
            } else {
              u = urlmod.format({
                host: "api.twitter.com",
                protocol: "https:",
                pathname: "/1.1/" + (friends ? 'friends' : 'followers') + "/ids.json",
                query: {
                  stringify_ids: true,
                  cursor: cursor,
                  screen_name: username,
                  count: 5000
                }
              });
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
                  funcname: "TwitterScraper.get_follower_ids"
                });
                _this._get_body_api({
                  url: u
                }, __iced_deferrals.defer({
                  assign_fn: (function() {
                    return function() {
                      err = arguments[0];
                      rc = arguments[1];
                      return json = arguments[2];
                    };
                  })(),
                  lineno: 222
                }));
                __iced_deferrals._fulfill();
              })(function() {
                _this.log("| get_followers " + username + " (" + cursor + ")");
                (function(__iced_k) {
                  if (err != null) {
                    return __iced_k(done = true);
                  } else {
                    (function(__iced_k) {
                      if (rc !== v_codes.OK) {
                        err = new Error("got bad code from get_body_api " + rc);
                        err.code = rc;
                        return __iced_k(done = true);
                      } else {
                        (function(__iced_k) {
                          var _i, _len, _ref1;
                          if ((typeof json !== "undefined" && json !== null ? json.ids : void 0) == null) {
                            err = new Error("got empty_json from get_body_api");
                            err.code = v_codes.EMPTY_JSON;
                            return __iced_k(done = true);
                          } else {
                            _ref1 = json.ids;
                            for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
                              x = _ref1[_i];
                              res.push(x);
                            }
                            (function(__iced_k) {
                              if (json.next_cursor && (res.length < stop_at)) {
                                cursor = json.next_cursor_str;
                                (function(__iced_k) {
                                  __iced_deferrals = new iced.Deferrals(__iced_k, {
                                    parent: ___iced_passed_deferral,
                                    filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
                                    funcname: "TwitterScraper.get_follower_ids"
                                  });
                                  setTimeout(__iced_deferrals.defer({
                                    lineno: 238
                                  }), cursor_wait);
                                  __iced_deferrals._fulfill();
                                })(__iced_k);
                              } else {
                                return __iced_k(done = true);
                              }
                            })(function() {
                              return __iced_k(_this.log("| got " + json.ids.length + " more; total=" + res.length));
                            });
                          }
                        })(__iced_k);
                      }
                    })(__iced_k);
                  }
                })(_next);
              });
            }
          };
          _while(__iced_k);
        });
      })(this)((function(_this) {
        return function() {
          return cb(err, res);
        };
      })(this));
    };

    TwitterScraper.prototype._id_to_url = function(username, status_id) {
      return "https://twitter.com/" + username + "/status/" + status_id;
    };

    TwitterScraper.prototype._check_api_url = function(_arg) {
      var api_url, username;
      api_url = _arg.api_url, username = _arg.username;
      return api_url.indexOf("https://twitter.com/" + username + "/") === 0;
    };

    TwitterScraper.prototype._validate_text_check = function(_arg) {
      var err, msg, proof_text_check, short_id, signature, _ref1;
      signature = _arg.signature, proof_text_check = _arg.proof_text_check;
      _ref1 = decode_sig({
        armored: signature
      }), err = _ref1[0], msg = _ref1[1];
      if (err == null) {
        short_id = make_ids(msg.body).short_id;
        if (proof_text_check.indexOf(" " + short_id + " ") < 0) {
          err = new Error("Cannot find " + short_id + " in " + proof_text_check);
        }
      }
      return err;
    };

    TwitterScraper.prototype.find_sig_in_tweet = function(_arg) {
      var html, inside, m, p, proof_text_check, rc, tweet_p, x;
      inside = _arg.inside, tweet_p = _arg.tweet_p, proof_text_check = _arg.proof_text_check;
      if ((tweet_p != null) && (inside == null)) {
        inside = tweet_p.text();
        html = tweet_p.html();
      } else {
        html = null;
      }
      inside = ws_normalize(inside);
      proof_text_check = ws_normalize(proof_text_check);
      this.log("+ Checking tweet '" + inside + "' for signature '" + proof_text_check + "'");
      if (html != null) {
        this.log("| html is: " + html);
      }
      x = /^(@[a-zA-Z0-9_-]+\s+)/;
      while ((m = inside.match(x)) != null) {
        p = m[1];
        inside = inside.slice(p.length);
        this.log("| Stripping off @prefix: " + p);
      }
      rc = inside.indexOf(proof_text_check) === 0 ? v_codes.OK : v_codes.DELETED;
      this.log("- Result -> " + rc);
      return rc;
    };

    TwitterScraper.prototype.check_status = function(_arg, cb) {
      var $, api_url, div, err, html, p, proof_text_check, rc, remote_id, username, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      username = _arg.username, api_url = _arg.api_url, proof_text_check = _arg.proof_text_check, remote_id = _arg.remote_id;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
            funcname: "TwitterScraper.check_status"
          });
          _this._get_url_body({
            url: api_url
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                rc = arguments[1];
                return html = arguments[2];
              };
            })(),
            lineno: 298
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          if (rc === v_codes.OK) {
            $ = _this.libs.cheerio.load(html);
            div = $('.permalink-tweet-container .permalink-tweet');
            if (!div.length) {
              rc = v_codes.FAILED_PARSE;
            } else {
              div = div.first();
              rc = !(sncmp(username, div.data('screenName'))) ? v_codes.BAD_USERNAME : ("" + remote_id) !== ("" + div.data('tweetId')) ? v_codes.BAD_REMOTE_ID : ((p = div.find('p.tweet-text')) == null) || !p.length ? v_codes.MISSING : _this.find_sig_in_tweet({
                tweet_p: p.first(),
                proof_text_check: proof_text_check
              });
            }
          }
          return cb(err, rc);
        };
      })(this));
    };

    TwitterScraper.prototype._get_bearer_token = function(cb) {
      var bt, err, rc, tok, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      bt = bearer_token({
        base: this
      });
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
            funcname: "TwitterScraper._get_bearer_token"
          });
          bt.get(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                return tok = arguments[1];
              };
            })(),
            lineno: 328
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          rc = typeof err !== "undefined" && err !== null ? v_codes.AUTH_FAILED : v_codes.OK;
          return cb(err, rc, tok);
        };
      })(this));
    };

    TwitterScraper.prototype._get_body_api = function(_arg, cb) {
      var args, body, err, rc, tok, url, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      url = _arg.url;
      rc = body = err = null;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
            funcname: "TwitterScraper._get_body_api"
          });
          _this._get_bearer_token(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                rc = arguments[1];
                return tok = arguments[2];
              };
            })(),
            lineno: 337
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          (function(__iced_k) {
            if (err == null) {
              _this.log("| HTTP API request for URL '" + url + "'");
              args = {
                url: url,
                headers: {
                  Authorization: "Bearer " + tok,
                  method: "GET"
                },
                json: true
              };
              (function(__iced_k) {
                __iced_deferrals = new iced.Deferrals(__iced_k, {
                  parent: ___iced_passed_deferral,
                  filename: "/home/jacko/keybase-proofs/src/scrapers/twitter.iced",
                  funcname: "TwitterScraper._get_body_api"
                });
                _this._get_url_body(args, __iced_deferrals.defer({
                  assign_fn: (function() {
                    return function() {
                      err = arguments[0];
                      rc = arguments[1];
                      return body = arguments[2];
                    };
                  })(),
                  lineno: 346
                }));
                __iced_deferrals._fulfill();
              })(__iced_k);
            } else {
              return __iced_k();
            }
          })(function() {
            return cb(err, rc, body);
          });
        };
      })(this));
    };

    return TwitterScraper;

  })(BaseScraper);

}).call(this);
