var is_iphone = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i); var is_ipad = navigator.userAgent.match(/iPad/i); var is_android = navigator.userAgent.match(/Android/i); var is_mobile = is_iphone || is_ipad || is_android; var is_desktop = !is_mobile; document.body.classList.add(is_desktop ? "desktop" : "mobile"); const AUDIO_REGEXP = /\.(mp3|wav|aif|aiff|ogg|opus|flac)$/i; const IMAGE_REGEXP = /\.(gif|jpg|jpeg|png)$/i; const CONTAINS_IMAGE_URL_REGEXP = /http\S+\.(gif|jpe?g|png)/i; function choice(a) { return a[randint(a.length)]; } function csrf() { return $("[name=_csrf]").attr("value"); } function bold_terms(s, terms) { s = sanitizeHTML(s); terms.forEach((term) => { s = s.replace(new RegExp(term, "ig"), "" + term + ""); }); return s; } function querystring(opt) { return ( "?" + Object.keys(opt) .map((key) => { return encodeURIComponent(key) + "=" + encodeURIComponent(opt[key]); }) .join("&") ); } function commatize(n, radix) { radix = radix || 1000; var nums = [], i, counter = 0, r = Math.floor; if (radix !== -1 && n > radix) { n /= radix; nums.unshift(r((n * 10) % 10)); nums.unshift("."); } do { i = r(n % 10); n = r(n / 10); counter += 1; if (n && !(counter % 3)) { i = " " + r(i); } nums.unshift(i); } while (n); return nums.join(""); } function privacy_dot(p) { if (!p) return "·"; else return ".:"; } var short_months = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "); function verbose_date(date, no_pad_hours) { var date = new Date(date * 1000); var d = date.getDate(); var m = date.getMinutes(); var h = date.getHours(); var meridian; if (h == 0) { h = 12; meridian = " am"; } else if (h == 12) { meridian = " pm"; } else if (h > 12) { h -= 12; meridian = " pm"; } else { meridian = " am"; } if (d < 10) d = "0" + d; if (m < 10) m = "0" + m; if (!no_pad_hours && h < 10) h = "0" + h; // non-breaking hyphen: ‑ var date = d + " " + short_months[date.getMonth()] + " " + date.getFullYear(); var time = h + ":" + m + meridian; return [date, time]; } function carbon_date(date, no_bold) { var span = +new Date() / 1000 - date; if (!no_bold && span < 86400) { // modified today color = "new"; } else if (span < 604800) { // modifed this week color = "recent"; } else if (span < 1209600) { // modifed 2 weeks ago color = "med"; } else if (span < 3024000) { // modifed 5 weeks ago color = "old"; } else if (span < 12315200) { // modifed 6 months ago color = "older"; } else { color = "quiet"; } return color; } function hush_views(n, bias, no_bold) { var txt = commatize(n, 1000); bias = bias || 1; n = n || 0; if (n < 30) { return ["quiet", n + " v."]; } if (n < 200) { return ["quiet", txt + " v."]; } else if (n < 500) { return ["old", txt + " v."]; } else if (n < 1000) { return ["med", txt + " v."]; } else if (n < 5000) { return ["recent", txt + " kv."]; } else if (no_bold || n < 10000) { return ["recent", txt + " kv."]; } else { return ["new", txt + " kv."]; } } function hush_threads(n, bias, no_bold) { var txt = commatize(n, -1); bias = bias || 1; n = n || 0; if (n < 10) { return ["quiet", n + " t."]; } else if (n < 25) { return ["old", txt + " t."]; } else if (n < 50) { return ["med", txt + " t."]; } else if (no_bold || n < 100) { return ["recent", txt + " t."]; } else { return ["new", txt + " t."]; } } function hush_size(n, bias, no_bold) { var txt = commatize(Math.floor(n / 1024), 1000); bias = 1 || bias; n = n || 0; if (n < 1024) { return ["quiet", n + " b."]; } if (n < 1000 * 1000) { return ["quiet", txt + " kb."]; } if (n < 20000000 / bias) { return ["quiet", txt + " mb."]; } if (n < 50000000 / bias) { return ["old", txt + " mb."]; } if (n < 80000000 / bias) { return ["med", txt + " mb."]; } if (no_bold || n < 170000000 / bias) { return ["recent", txt + " mb."]; } if (n >= 10000 * 1000 * 1000) { console.log(n); txt = commatize(Math.floor(n / (1024 * 1024 * 1024))); return ["new", txt + " gb."]; } return ["new", txt + " mb."]; } function hush_null(n, unit, no_bold) { n = commatize(n, -1); var s = unit ? n + " " + unit + "." : n; if (n < 3) { return ["quiet", s]; } else if (n < 6) { return ["older", s]; } else if (n < 10) { return ["old", s]; } else if (n < 16) { return ["med", s]; } else if (no_bold || n < 21) { return ["recent", s]; } else { return ["new", s]; } } function courtesy_s(n, s) { return n == 1 ? "" : s || "s"; } var revision_letters = "z a b c d f g h j k l m n p q r s t v w x y".split(" "); function get_revision(thread) { if (!thread.revision) return ""; var rev = thread.revision; var n = 0; var digits = ""; do { n = rev % 21; rev = Math.floor(rev / 21); digits = revision_letters[n] + digits; } while (rev !== 0); return digits; } function get_age(t, long) { var age = Math.abs(Date.now() / 1000 - t); var r = Math.floor; var m; if (age < 5) { return "now"; } if (age < 60) { return r(age) + (long ? " seconds" : "s"); } age /= 60; if (age < 60) { return r(age) + (long ? " minutes" : "m"); } m = r(age % 60); age /= 60; if (m > 0 && age < 2) { return r(age) + (long ? " hours " + m + " minutes" : "h" + m + "m"); } if (age < 24) { return r(age) + (long ? " hours" : "h"); } age /= 24; if (age < 7) { return r(age) + (long ? " days" : "d"); } age /= 7; if (age < 12) { return r(age) + (long ? " weeks" : "w"); } age /= 4; if (age < 12) { return r(age) + (long ? " months" : "m"); } age /= 12; return r(age) + (long ? " years" : "y"); } const age_scale = [ [0, 1.0], [60 * 10, 1.0], [60 * 60, 0.975], [60 * 60 * 8, 0.95], [60 * 60 * 24, 0.925], [60 * 60 * 24 * 7, 0.9], [60 * 60 * 24 * 7 * 4, 0.875], [60 * 60 * 24 * 7 * 4 * 12, 0.85], ]; function get_age_opacity(t) { var age = Math.abs(Date.now() / 1000 - t); return get_scale_opacity(age, age_scale); } const size_scale = [ [0, 0.0], [1, 0.7], [5, 0.8], [10, 0.9], [15, 0.95], [20, 0.99], ]; function get_size_opacity(n) { return get_scale_opacity(n, size_scale); } const views_scale = [ [0, 0.5], [100, 0.8], [1000, 0.9], [10000, 1.0], ]; function get_views_opacity(n) { return get_scale_opacity(n, views_scale); } /** * find a value on one axis of an array of points, and return the proportional point * @param {Array} value a value, to be matched on the first column of scale * @param {Array} scale an array of points: (value, target) * @return {Number} a proportional point within the closest target values */ function get_scale_opacity(value, scale) { for (let i = 1; i < scale.length; i++) { const [max_value, max_lerp] = scale[i]; if (value === max_value) { return max_lerp; } if (value < max_value) { const [min_value, min_lerp] = scale[i - 1]; return lerp(norm(value, min_value, max_value), min_lerp, max_lerp); } } return scale[scale.length - 1][1]; } function trimComment({ isViewingThread, lines, snippetSize, cropSize }) { return function (comment) { return isViewingThread || comment.comment.length < (cropSize || 256) ? comment : { ...comment, comment: comment.comment .split("\n") .slice(0, lines || 5) .join("\n") .substr(0, snippetSize || 512) .replace(/\s+\w+$/, "") .replace(/.*/m, "") .replace(/
.*/m, "")
              .replace(/.*/m, "")
              .replace(/<[^>]+$/m, "") +
            `... Read more...`,
        };
  };
}

function tidy_urls(s, short_urls) {
  var ret = (s || "")
    .split("\n")
    .map(function (line) {
      if (line.indexOf("<") !== -1) {
        return line;
      }
      return line.replace(/https?:\/\/[^ ]+/g, function (url) {
        if (is_image(url)) {
          return (
            ''
          );
        } else if (short_urls) {
          return (
            '[' +
            get_domain(url) +
            "]"
          );
        } else {
          return (
            '' +
            url +
            ""
          );
        }
      });
    })
    .join("\n")
    .replace(/\r/g, "")
    .replace(/\n/g, "")
    .replace(/<\/code>\n/g, "");
  return ret;
}
function get_domain(url) {
  return url
    .replace(/https?:\/\//, "")
    .replace(/\/.*/, "")
    .replace(/www\./, "");
}
function is_image(url) {
  return !!url.match(/\.(gif|jpe?g|png)(\?.*)?$/i);
}
function make_link(file) {
  if (file.storage) {
    return (
      "//s3.amazonaws.com/" +
      file.storage +
      sdk.opt.s3.path +
      "/data/" +
      file.thread +
      "/" +
      encodeURIComponent(file.filename)
    );
  }
  if (file.filename.indexOf("http") !== 0) {
    return "/data/" + file.thread + "/" + encodeURIComponent(file.filename);
  }
  return file.filename;
}
function profile_image(username) {
  return "//s3.amazonaws.com/i.asdf.us/bucky/profile/" + username + ".jpg";
}
function make_thumb(file) {
  if (file.storage) {
    return (
      "//s3.amazonaws.com/" +
      file.storage +
      sdk.opt.s3.path +
      "/data/" +
      file.thread +
      "/" +
      encodeURIComponent(file.filename)
    );
  }
  if (file.filename.indexOf("http") !== 0) {
    return "/data/" + file.thread + "/" + file.filename;
  }
  return "/data/" + file.thread + "/" + file.filename;
  // var partz = file.filename.toLowerCase().split("/")
  // return partz.splice(partz.length-2, 0, ".thumb").join("/")
}

var metadataTemplate = $(".metadata_template").html();
function metadata(thread) {
  var datetime = verbose_date(thread.createdate, true);
  var age = get_age(thread.lastmodified, true);
  var t = metadataTemplate
    .replace(/{{username}}/g, thread.username)
    .replace(/{{date}}/g, datetime[0])
    .replace(/{{time}}/g, datetime[1])
    .replace(/{{active}}/g, age + " ago")
    .replace(/{{views}}/g, thread.viewed + " view" + courtesy_s(thread.viewed));
  return t;
}