chromium/native_client_sdk/src/web/manifest.html

<!DOCTYPE html>
<!-- much of this is stolen from omahaproxy.appspot.com/viewer -->
<html>
  <head>
    <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
    <title>NaCl SDK Manifest Viewer</title>
  </head>
  <style type="text/css" media="screen">
    body {
      font-family: monospace;
      font-size: 10pt;
    }

    table {
      border-collapse: collapse;
      border-color: rgb(100, 100, 100);
      border-style: solid;
      border-width: 1px 0px 1px 0px;
    }

    table td {
      padding: 3px;
      border-color: rgb(100, 100, 100);
      border-style: solid;
      border-width: 0px 1px 0px 1px;
    }

    thead {
      background-color: lightblue;
      font-weight: bold;
      border-style: solid;
      border-color: rgb(100, 100, 100);
      border-width: 0px 0px 2px 0px;
      text-align: center;
    }

    tbody tr:nth-child(odd) {
      background-color: rgb(230, 230, 230);
    }

    tbody tr:hover {
      background-color: orange;
    }

    td a {
      padding: 3px;
    }

    #log > span {
      display: block;
    }

    #log > span.highlight {
      font-weight: bold;
    }

    #log > span.missing {
      color: #f00;
    }
  </style>
  <body>
    <h1>NaCl SDK Manifest Viewer</h1>
    <table>
      <thead id="columns">
      </thead>
      <tbody id="rows">
      </tbody>
    </table>
    <h2>Most recent upload log:</h2>
    <div id="log">
    </div>
    <script type="application/javascript">
      function loadText(url, callback) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function (e) {
          if (xhr.readyState == 4) {
            if (xhr.status == 200) {
              callback(xhr.responseText);
            } else {
              console.log("Failed to load "+url+": error " + xhr.status);
            }
          }
        }
        xhr.send(null);
      }

      function loadJson(url, callback) {
        loadText(url, function (text) {
          callback(JSON.parse(text));
        });
      }

      function removeAllChildren(elm) {
        while (elm.childNodes.length) {
          elm.removeChild(elm.firstChild);
        }
      }

      function display(data) {
        data = data.bundles;

        var columnsElm = document.getElementById('columns');
        var rowsElm = document.getElementById('rows');
        removeAllChildren(columnsElm);
        removeAllChildren(rowsElm);

        // Create the column headers.
        var tr = document.createElement('tr');
        var columns = [
          'name', 'version', 'revision', 'trunk_revision', 'chrome_version', 'win', 'mac', 'linux', 'all'
        ];
        columns.forEach(function(column) {
          var td = document.createElement('td');
          var text = document.createTextNode(column);
          td.appendChild(text);
          tr.appendChild(td);
        });
        columnsElm.appendChild(tr);

        data.forEach(function(row) {
          var tr = document.createElement('tr');
          columns.forEach(function(column) {
            var td = document.createElement('td');
            var node = makeCell(row, column);
            if (node) {
              td.appendChild(node);
            }
            tr.appendChild(td);
          });
          rowsElm.appendChild(tr);
        });
      }

      function makeCell(row, column) {
        var platforms = ['win', 'mac', 'linux', 'all'];

        if (platforms.indexOf(column) !== -1) {
          return makePlatformCell(row, column);
        } else if (column === 'trunk_revision') {
          return makeTrunkRevisionCell(row);
        } else if (column === 'chrome_version') {
          return makeChromeVersionCell(row);
        } else {
          return document.createTextNode(row[column]);
        }
      }

      function makePlatformCell(row, column) {
        var archives = row.archives;
        for (var k = 0; k < archives.length; ++k) {
          if (column !== archives[k].host_os) {
            continue;
          }

          // Convert the URL to a short name:
          // https://.../36.0.1974.2/naclsdk_linux.tar.bz2 -> naclsdk_linux
          var url = archives[k].url;
          var lastSlash = url.lastIndexOf('/');
          var nextDot = url.indexOf('.', lastSlash);
          var name = url.substr(lastSlash + 1, nextDot - lastSlash - 1);

          var node = document.createElement('a');
          node.setAttribute('href', url);
          node.appendChild(document.createTextNode(name));
          return node;
        }
        return null;
      }

      function makeTrunkRevisionCell(row) {
        var url = row.archives[0].url;
        var version = versionFromUrl(url);
        if (version) {
          var node = document.createTextNode('');
          baseTrunkRevisionFromVersion(version, function(node) {
            return function(revision) {
              node.textContent = revision;
            };
          }(node));
          return node;
        }
        return null;
      }

      function makeChromeVersionCell(row) {
        var url = row.archives[0].url;
        var version = versionFromUrl(url);
        if (version) {
          return document.createTextNode(version);
        }
        return null;
      }

      function versionFromUrl(url) {
        // Extract the Chrome version from an archive URL.
        // It should look something like:
        // https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/36.0.1974.2/naclsdk_win.tar.bz2
        var lastSlash = url.lastIndexOf('/');
        var penultimateSlash = url.lastIndexOf('/', lastSlash - 1);
        // The version is between these two slashes.
        var version = url.substr(penultimateSlash + 1,
                                 lastSlash - penultimateSlash - 1);
        // It is a chrome version if it matches one of these regexes:
        if (/trunk\.\d+/.test(version)) {
          // Trunk version.
          return version;
        } else if (/\d+\.\d+\.\d+\.\d+/.test(version)) {
          // Branch version.
          return version;
        } else {
          // Not a version.
          return null;
        }
      }

      function baseTrunkRevisionFromVersion(version, callback) {
        if (version.indexOf('trunk', 0) === 0) {
          callback(version.substr(6));  // Skip "trunk."
        } else {
          revisionFromVersion(baseTrunkVersionFromVersion(version), callback);
        }
      }

      function baseTrunkVersionFromVersion(version) {
        var lastDot = version.lastIndexOf('.');
        return version.substr(0, lastDot) + '.0';
      }

      function revisionFromVersion(version, callback) {
        var url = 'http://omahaproxy.appspot.com/revision.json?version='+version;
        loadJson(url, function(data) {
          callback(data.chromium_revision);
        });
      }

      function displayLog(text) {
        var lines = text.split('\n');
        var logEl = document.getElementById('log');
        lines.forEach(function (line) {
          var spanEl = document.createElement('span');
          spanEl.textContent = line;
          if (line.indexOf('>>>', 0) === 0) {
            spanEl.classList.add('highlight');
          } else if (line.indexOf('Missing archives') !== -1) {
            spanEl.classList.add('missing');
          }
          logEl.appendChild(spanEl);
        });
      }

      loadJson('naclsdk_manifest2.json', display);
      loadText('naclsdk_manifest2.json.log', displayLog);
    </script>
  </body>
</html>