<commit_before>function getLang() {
  return document.documentElement.lang;
} 

async function findCurrentPageLastModified() {
  // for android dev site 
  // <meta itemprop="dateModified" content="2017-07-27T14:36:46.324130">
  const meta = document.head.querySelector("meta[itemprop='dateModified'");
  if(meta) {
    return getDateAsUTC(meta.content);
  }

  // for firebase, google-dev, cloud, tensorflow
  // <p itemprop="datePublished" content="2017-08-07T20:49:39.902150">
  // This info maybe not in some pages.
  const p = document.querySelector("p[itemprop='datePublished'");
  if(p) {
    return getDateAsUTC(p.getAttribute("content"));
  }

  return await getHTTPLastModified(document.location.href);
}

function getDateAsUTC(datestr) {
  return new Date(datestr + 'Z')
}

async function findEnPageLastModified() {
  return await getHTTPLastModified(getEnPageUrl());
} 

async function getHTTPLastModified(url) {
  try {
    const option = {
      method: 'HEAD', 
      credentials: 'same-origin'
    }
    const response = await fetch(url, option);
    if(response.ok && response.headers.has("Last-Modified")) {
      // This is GMT timezone
      return new Date(response.headers.get("Last-Modified"));
    } else {
      return null;
    }
  } catch(e) {
    return null;
  }
}

function getEnPageUrl() {
  const params = new URLSearchParams(location.search);
  // set ?hl=en param
  params.set('hl', 'en');
  return `${location.pathname}?${params}`;
}

var pageData = null;

async function init() {
  const lang = getLang();
  if(!lang || lang === "en") {
    return
  }

  const curUpdateTime = await findCurrentPageLastModified();
  if(!curUpdateTime) {
    return
  }

  const oriUpdateTime = await findEnPageLastModified();
  if(!oriUpdateTime) {
    return
  }
  
  // console.log("curUpdateTime: " + curUpdateTime);
  // console.log("oriUpdateTime: " + oriUpdateTime);

  pageData = {
    oriUpdateTime: oriUpdateTime.getTime(),
    curUpdateTime: curUpdateTime.getTime(),
    enURL: location.protocol 
          + "//" 
          + location.hostname
          + getEnPageUrl(),
    curURL: document.location.href
  }

  const data = {
    oriUpdateTime: oriUpdateTime.getTime(),
    curUpdateTime: curUpdateTime.getTime()
  }
  // send to event page to show icon.
  chrome.runtime.sendMessage(data);

  // show warning banner
  chrome.storage.sync.get({
    showBanner: true // default true
  }, function(items) {
    if(items.showBanner) {
      showBanner();
    }
  });
}

/**
 * Show warning banner in the page.
 * This is the same logic with popup.js
 */
function showBanner() {
  const diff = pageData.oriUpdateTime - pageData.curUpdateTime;
  if(diff <= 60*30*1000) { // up to date or less than 30min
    return;
  }

  // container element
  const container = document.createElement('div');
  const oneDay = 3600*24*1000;
  const noteString = chrome.i18n.getMessage("note");
  if(diff >= oneDay) { // behind more than 1 days
    const days = Math.trunc(diff/oneDay);
    container.innerHTML = noteString + chrome.i18n.getMessage("behindDays", [days, pageData.enURL]);
  } else if(diff > 0) { // behind less than 1 day
    container.innerHTML = noteString + chrome.i18n.getMessage("behindLessThanOneDay", [pageData.enURL]);
  }
  container.style.cssText = "position:fixed; width: 314px; margin-left: -157px; top: 12%; left: 50%; color: blue; border: 2px solid red; background-color: yellow; z-index: 1000000; font-size: 12px; padding: 3px;"; 
  // close element
  const close = document.createElement('span');
  close.innerText = "[X]";
  close.title = "close";
  close.style.cssText = "cursor: pointer;";
  close.onclick = function(){
    close.parentElement.hidden = true;
  };
  container.appendChild(close);
  // add to body
  document.body.appendChild(container);
}

// reponse popup to get page info.
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if(sender.tab) {
      return;
    }
    sendResponse(pageData);
  }
);

init();<commit_msg>support MDN, trim ending spaces.<commit_after>function getLang() {
  return document.documentElement.lang;
}

async function findCurrentPageLastModified() {
  // for MDN
  if(location.hostname === "developer.mozilla.org") {
    return findMDNPageLastModified(document);
  }

  // for android dev site
  // <meta itemprop="dateModified" content="2017-07-27T14:36:46.324130">
  const meta = document.head.querySelector("meta[itemprop='dateModified'");
  if(meta) {
    return getDateAsUTC(meta.content);
  }

  // for firebase, google-dev, cloud, tensorflow
  // <p itemprop="datePublished" content="2017-08-07T20:49:39.902150">
  // This info maybe not in some pages.
  const p = document.querySelector("p[itemprop='datePublished'");
  if(p) {
    return getDateAsUTC(p.getAttribute("content"));
  }

  return await getHTTPLastModified(document.location.href);
}

function getDateAsUTC(datestr) {
  return new Date(datestr + 'Z')
}

async function findEnPageLastModified() {
  // for MDN
  if(location.hostname === "developer.mozilla.org") {
    return findMDNEnPageLastModified();
  }
  // other google devsites
  return await getHTTPLastModified(getEnPageUrl());
}

async function getHTTPLastModified(url) {
  try {
    const option = {
      method: 'HEAD',
      credentials: 'same-origin'
    }
    const response = await fetch(url, option);
    if(response.ok && response.headers.has("Last-Modified")) {
      // This is GMT timezone
      return new Date(response.headers.get("Last-Modified"));
    } else {
      return null;
    }
  } catch(e) {
    return null;
  }
}

function getEnPageUrl() {
  const params = new URLSearchParams(location.search);
  // set ?hl=en param
  params.set('hl', 'en');
  return `${location.pathname}?${params}`;
}

function getMDNEnPageUrl() {
  // replace developer.mozilla.org/zh-CN/ to /en-US/
  const enAlternate = document.head.querySelector("link[rel=alternate][hreflang=en-US]");
  return enAlternate ? enAlternate.href : null;
}

async function findMDNEnPageLastModified() {
  const enURL = getMDNEnPageUrl();
  if(enURL) {
    const response = await fetch(enURL);
    const html = await response.text();
    const enHTML = new DOMParser().parseFromString(html, 'text/html');
    return findMDNPageLastModified(enHTML);
  }
  return null;
}

function findMDNPageLastModified(dom) {
  // a time element
  const lastUpdateTime = dom.querySelector(".contributors-sub time");
  if(lastUpdateTime) {
    return new Date(lastUpdateTime.dateTime);
  }
  return null;
}

var pageData = null;

async function init() {
  const lang = getLang();
  if(!lang || lang === "en" || lang === "en-US") {
    return
  }

  const curUpdateTime = await findCurrentPageLastModified();
  if(!curUpdateTime) {
    return
  }

  const oriUpdateTime = await findEnPageLastModified();
  if(!oriUpdateTime) {
    return
  }

  // console.log("curUpdateTime: " + curUpdateTime);
  // console.log("oriUpdateTime: " + oriUpdateTime);

  let enURL;
  if(location.hostname === "developer.mozilla.org") {
    enURL = getMDNEnPageUrl();
  } else {
    enURL = location.protocol
          + "//"
          + location.hostname
          + getEnPageUrl();
  }

  pageData = {
    oriUpdateTime: oriUpdateTime.getTime(),
    curUpdateTime: curUpdateTime.getTime(),
    enURL: enURL,
    curURL: document.location.href
  }

  const data = {
    oriUpdateTime: oriUpdateTime.getTime(),
    curUpdateTime: curUpdateTime.getTime()
  }
  // send to event page to show icon.
  chrome.runtime.sendMessage(data);

  // show warning banner
  chrome.storage.sync.get({
    showBanner: true // default true
  }, function(items) {
    if(items.showBanner) {
      showBanner();
    }
  });
}

/**
 * Show warning banner in the page.
 * This is the same logic with popup.js
 */
function showBanner() {
  const diff = pageData.oriUpdateTime - pageData.curUpdateTime;
  if(diff <= 60*30*1000) { // up to date or less than 30min
    return;
  }

  // container element
  const container = document.createElement('div');
  const oneDay = 3600*24*1000;
  const noteString = chrome.i18n.getMessage("note");
  if(diff >= oneDay) { // behind more than 1 days
    const days = Math.trunc(diff/oneDay);
    container.innerHTML = noteString + chrome.i18n.getMessage("behindDays", [days, pageData.enURL]);
  } else if(diff > 0) { // behind less than 1 day
    container.innerHTML = noteString + chrome.i18n.getMessage("behindLessThanOneDay", [pageData.enURL]);
  }
  container.style.cssText = "position:fixed; width: 314px; margin-left: -157px; top: 12%; left: 50%; color: blue; border: 2px solid red; background-color: yellow; z-index: 1000000; font-size: 12px; padding: 3px;";
  // close element
  const close = document.createElement('span');
  close.innerText = "[X]";
  close.title = "close";
  close.style.cssText = "cursor: pointer;";
  close.onclick = function(){
    close.parentElement.hidden = true;
  };
  container.appendChild(close);
  // add to body
  document.body.appendChild(container);
}

// reponse popup to get page info.
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if(sender.tab) {
      return;
    }
    sendResponse(pageData);
  }
);

init();

{'fraction_non_alphanumeric': 0.13857515204170287, 'fraction_numerical': 0.01954821894005213, 'mean_word_length': 3.5544015825914936, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3048953', 'n_tokens_mistral': 3135, 'n_tokens_neox': 2946, 'n_words': 661}