You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by ac...@apache.org on 2025/02/27 01:38:28 UTC

(kudu) branch gh-pages updated: [site] Remove thirdparty resource references

This is an automated email from the ASF dual-hosted git repository.

achennaka pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/gh-pages by this push:
     new 015e24c98 [site] Remove thirdparty resource references
015e24c98 is described below

commit 015e24c9854239e1bd4f51f18e28482f8b993215
Author: root <ro...@ccycloud.docs-kudu.root.comops.site>
AuthorDate: Mon Feb 10 23:36:31 2025 -0800

    [site] Remove thirdparty resource references
    
    This commit updates Kudu website by removing any resource reference
    to any thirparty hosted website and replacing them with files in the
    local repo. This is needed to ensure the site works as expected once
    the CSP blocking is in effect by Apache from March 1.
    
    This commit also reverts commit 55b58c as the approach taken did not
    work as expected.
    
    Also updated site_tool script to use the correct command for html-proofer
    and removed the verbose option as it is not present anymore.
    
    Change-Id: I5971a406968bc69fc21bbd05618d85e702210539
    Reviewed-on: http://gerrit.cloudera.org:8080/22472
    Reviewed-by: Alexey Serbin <al...@apache.org>
    Tested-by: Abhishek Chennaka <ac...@cloudera.com>
---
 Gemfile.lock                                       |   4 +-
 _includes/bottom_common.html                       |   8 +-
 _includes/top_common.html                          |  13 +-
 ...-07-30-building-near-real-time-big-data-lake.md |  21 +-
 img/apachekudu_logo_0716_160px.png                 | Bin 0 -> 8404 bytes
 img/apachekudu_logo_0716_290px.png                 | Bin 0 -> 17306 bytes
 img/apachekudu_logo_0716_345px.png                 | Bin 0 -> 21572 bytes
 img/apachekudu_logo_0716_580px.png                 | Bin 0 -> 38943 bytes
 img/apachekudu_logo_0716_690px.png                 | Bin 0 -> 47047 bytes
 img/apachekudu_logo_0716_80px.png                  | Bin 0 -> 3706 bytes
 img/boristyukin.com/nifi_initial.png               | Bin 0 -> 138081 bytes
 img/boristyukin.com/nifi_rt.png                    | Bin 0 -> 129932 bytes
 img/boristyukin.com/pipelinearchitecture.png       | Bin 0 -> 305515 bytes
 img/boristyukin.com/query1.png                     | Bin 0 -> 15619 bytes
 img/boristyukin.com/query2.png                     | Bin 0 -> 15401 bytes
 img/boristyukin.com/query3.png                     | Bin 0 -> 25717 bytes
 img/envelope_12px.png                              | Bin 0 -> 2942 bytes
 img/gerrit_mark_16px.png                           | Bin 0 -> 468 bytes
 img/github_mark_16px.png                           | Bin 0 -> 505 bytes
 img/github_mark_light_16px.png                     | Bin 0 -> 404 bytes
 img/jira_mark_16px.png                             | Bin 0 -> 232 bytes
 img/jira_mark_white_16px.png                       | Bin 0 -> 215 bytes
 img/slack_mark_16px.png                            | Bin 0 -> 769 bytes
 img/slack_mark_white_16px.png                      | Bin 0 -> 479 bytes
 img/twitter_mark_16px.png                          | Bin 0 -> 438 bytes
 img/twitter_mark_white_16px.png                    | Bin 0 -> 399 bytes
 js/anchor.js                                       | 322 +++++++++++++++++++++
 js/bootstrap.min.js                                |   7 +
 js/jquery.min.js                                   |   6 +
 site_tool                                          |   3 +-
 30 files changed, 356 insertions(+), 28 deletions(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index 38946cd48..f750f8ad9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -54,7 +54,7 @@ GEM
       kramdown (~> 2.0)
     libv8 (3.16.14.19)
     liquid (4.0.3)
-    listen (3.2.1)
+    listen (3.9.0)
       rb-fsevent (~> 0.10, >= 0.10.3)
       rb-inotify (~> 0.9, >= 0.9.10)
     mercenary (0.4.0)
@@ -101,4 +101,4 @@ DEPENDENCIES
   therubyracer
 
 BUNDLED WITH
-   2.1.4
+   2.5.23
diff --git a/_includes/bottom_common.html b/_includes/bottom_common.html
index 29a1aa00b..b61bfe040 100644
--- a/_includes/bottom_common.html
+++ b/_includes/bottom_common.html
@@ -18,7 +18,7 @@
         </div>
       </footer>
     </div>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+    <script src="/js/jquery.min.js"></script>
     <script>
       // Try to detect touch-screen devices. Note: Many laptops have touch screens.
       $(document).ready(function() {
@@ -29,10 +29,8 @@
         }
       });
     </script>
-    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
-            integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
-            crossorigin="anonymous"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/3.1.0/anchor.js"></script>
+    <script src="/js/bootstrap.min.js"></script>
+    <script src="/js/anchor.js"></script>
     <script>
       anchors.options = {
         placement: 'right',
diff --git a/_includes/top_common.html b/_includes/top_common.html
index 5e84df44b..bc7c3c5f1 100644
--- a/_includes/top_common.html
+++ b/_includes/top_common.html
@@ -7,15 +7,6 @@
     <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
     <meta name="description" content="A new open source Apache Hadoop ecosystem project, Apache Kudu completes Hadoop's storage layer to enable fast analytics on fast data" />
     <meta name="author" content="Cloudera" />
-    <meta http-equiv="Content-Security-Policy" content="
-      default-src 'self';
-      script-src 'self' https://kudu.apache.org https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://maxcdn.bootstrapcdn.com 'unsafe-inline';
-      style-src 'self' https://kudu.apache.org https://fonts.googleapis.com https://maxcdn.bootstrapcdn.com 'unsafe-inline';
-      font-src 'self' https://fonts.gstatic.com https://maxcdn.bootstrapcdn.com data:;
-      img-src 'self' https://kudu.apache.org https://d3dr9sfxru4sde.cloudfront.net https://www.apache.org data:;
-      base-uri 'self';
-      form-action 'self';
-    ">
     <title>Apache Kudu - {{ page.title }}</title>
     <!-- Bootstrap core CSS -->
     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
@@ -54,8 +45,8 @@
               </button>
               {% if page.active_nav != 'home' %}
               <a class="logo" href="{{site.github.url}}/"><img
-                src="//d3dr9sfxru4sde.cloudfront.net/i/k/apachekudu_logo_0716_80px.png"
-                srcset="//d3dr9sfxru4sde.cloudfront.net/i/k/apachekudu_logo_0716_80px.png 1x, //d3dr9sfxru4sde.cloudfront.net/i/k/apachekudu_logo_0716_160px.png 2x"
+                src="/img/apachekudu_logo_0716_80px.png"
+                srcset="/img/apachekudu_logo_0716_80px.png 1x, /img/apachekudu_logo_0716_160px.png 2x"
                 alt="Apache Kudu"/></a>
               {% endif %}
             </div>
diff --git a/_posts/2020-07-30-building-near-real-time-big-data-lake.md b/_posts/2020-07-30-building-near-real-time-big-data-lake.md
index 81471ff6e..24e3d3839 100644
--- a/_posts/2020-07-30-building-near-real-time-big-data-lake.md
+++ b/_posts/2020-07-30-building-near-real-time-big-data-lake.md
@@ -114,8 +114,8 @@ product you desire and trust. One of these products for us was Apache NiFi, whic
 tremendous value.
 
 After a lot of trials and errors, we decided on this architecture:
-
-<img src="https://boristyukin.com/content/images/pipelinearchitecture.png" width="100%"/>
+<!--Image downloaded from https://boristyukin.com/content/images/pipelinearchitecture.png-->
+<img src="/img/boristyukin.com/pipelinearchitecture.png" width="100%"/>
 
 One of the toughest challenges we faced right away was the fact that most of the Big Data data
 engines were not designed to support mutable data but rather immutable append-only data. All the
@@ -149,7 +149,8 @@ Initial ingest is pretty typical - we use Sqoop to extract data from Cerner Orac
 NiFi helps orchestrate initial load for hundreds of tables. Actually, this NiFi flow below can
 handle initial ingest of hundreds of tables!
 
-<img src="https://boristyukin.com/content/images/nifi_initial.png" width="100%" />
+<!--Image downloaded from https://boristyukin.com/content/images/nifi_initial.png-->
+<img src="/img/boristyukin.com/nifi_initial.png" width="100%" />
 
 Our secret sauce though is [MetaZoo](http://boristyukin.com/how-to-ingest-a-large-number-of-tables-into-a-big-data-lake-or-why-i-built-metazoo/).
 MetaZoo generates optimal parameters for Sqoop (such as a number of mappers, split-by column, and so
@@ -198,7 +199,8 @@ without much impact.
 Below is the NiFi flow than handles real-time streaming from Oracle/GoldenGate/Kafka and persists
 data into Kudu:
 
-<img src="https://boristyukin.com/content/images/nifi_rt.png" width="100%"/>
+<!--Image downloaded from https://boristyukin.com/content/images/nifi_rt.png-->
+<img src="/img/boristyukin.com/nifi_rt.png" width="100%"/>
 
 1. NiFi flow consumes Kafka messages, produced by GoldenGate. Every table from every domain has
 its own Kafka topic. Topics have only one partition to preserve the original order of messages.
@@ -231,18 +233,21 @@ scalability of Big Data technology.
 Here, I run a query in Impala to count patients, admitted to our hospitals within the last 7 days,
 who are still in the hospitals (not discharged yet):
 
-![query 1](https://boristyukin.com/content/images/query1.png)
+<!--Image downloaded from https://boristyukin.com/content/images/query1.png-->
+![query 1](/img/boristyukin.com/query1.png)
 
 Then 5 seconds later I run the same query again to see numbers changed - more patients got admitted
 and discharged:
 
-![query 2](https://boristyukin.com/content/images/query2.png)]
+<!--Image downloaded from https://boristyukin.com/content/images/query2.png-->
+![query 2](/img/boristyukin.com/query2.png)]
 
 This query below counts certain clinical events in the 20B row Kudu table (which is updated in near
 real-time). While it takes 28 seconds to finish, this query would never even finish I ran it against
 our Oracle database. It found 13.7B events:
 
-![query 3](https://boristyukin.com/content/images/query3.png)
+<!--Image downloaded from https://boristyukin.com/content/images/query3.png-->
+![query 3](/img/boristyukin.com/query3.png)
 
 ## Credits
 Apache Impala, Apache Kudu and Apache NiFi were the pillars of our real-time pipeline. Back in 2017,
@@ -254,4 +259,4 @@ We were amazed by all the help, dedication, knowledge sharing, friendliness, and
 NiFi and Kudu developers. Huge thank you to all of you who helped us alone the way. You guys are
 amazing and you are building fantastic products!
 
-To be continued...
\ No newline at end of file
+To be continued...
diff --git a/img/apachekudu_logo_0716_160px.png b/img/apachekudu_logo_0716_160px.png
new file mode 100644
index 000000000..3c2bf37c0
Binary files /dev/null and b/img/apachekudu_logo_0716_160px.png differ
diff --git a/img/apachekudu_logo_0716_290px.png b/img/apachekudu_logo_0716_290px.png
new file mode 100644
index 000000000..6dea3ea03
Binary files /dev/null and b/img/apachekudu_logo_0716_290px.png differ
diff --git a/img/apachekudu_logo_0716_345px.png b/img/apachekudu_logo_0716_345px.png
new file mode 100644
index 000000000..1afca8976
Binary files /dev/null and b/img/apachekudu_logo_0716_345px.png differ
diff --git a/img/apachekudu_logo_0716_580px.png b/img/apachekudu_logo_0716_580px.png
new file mode 100644
index 000000000..4a8146fb4
Binary files /dev/null and b/img/apachekudu_logo_0716_580px.png differ
diff --git a/img/apachekudu_logo_0716_690px.png b/img/apachekudu_logo_0716_690px.png
new file mode 100644
index 000000000..0ecbab7d1
Binary files /dev/null and b/img/apachekudu_logo_0716_690px.png differ
diff --git a/img/apachekudu_logo_0716_80px.png b/img/apachekudu_logo_0716_80px.png
new file mode 100644
index 000000000..8d9349b2d
Binary files /dev/null and b/img/apachekudu_logo_0716_80px.png differ
diff --git a/img/boristyukin.com/nifi_initial.png b/img/boristyukin.com/nifi_initial.png
new file mode 100644
index 000000000..cb09230f5
Binary files /dev/null and b/img/boristyukin.com/nifi_initial.png differ
diff --git a/img/boristyukin.com/nifi_rt.png b/img/boristyukin.com/nifi_rt.png
new file mode 100644
index 000000000..69c0e31ae
Binary files /dev/null and b/img/boristyukin.com/nifi_rt.png differ
diff --git a/img/boristyukin.com/pipelinearchitecture.png b/img/boristyukin.com/pipelinearchitecture.png
new file mode 100644
index 000000000..52ac09f19
Binary files /dev/null and b/img/boristyukin.com/pipelinearchitecture.png differ
diff --git a/img/boristyukin.com/query1.png b/img/boristyukin.com/query1.png
new file mode 100644
index 000000000..e047bc285
Binary files /dev/null and b/img/boristyukin.com/query1.png differ
diff --git a/img/boristyukin.com/query2.png b/img/boristyukin.com/query2.png
new file mode 100644
index 000000000..8c2201ea2
Binary files /dev/null and b/img/boristyukin.com/query2.png differ
diff --git a/img/boristyukin.com/query3.png b/img/boristyukin.com/query3.png
new file mode 100644
index 000000000..9e6562667
Binary files /dev/null and b/img/boristyukin.com/query3.png differ
diff --git a/img/envelope_12px.png b/img/envelope_12px.png
new file mode 100644
index 000000000..3c3f9a52d
Binary files /dev/null and b/img/envelope_12px.png differ
diff --git a/img/gerrit_mark_16px.png b/img/gerrit_mark_16px.png
new file mode 100644
index 000000000..1b399d491
Binary files /dev/null and b/img/gerrit_mark_16px.png differ
diff --git a/img/github_mark_16px.png b/img/github_mark_16px.png
new file mode 100644
index 000000000..2d4c1519a
Binary files /dev/null and b/img/github_mark_16px.png differ
diff --git a/img/github_mark_light_16px.png b/img/github_mark_light_16px.png
new file mode 100644
index 000000000..7726b90b9
Binary files /dev/null and b/img/github_mark_light_16px.png differ
diff --git a/img/jira_mark_16px.png b/img/jira_mark_16px.png
new file mode 100644
index 000000000..89a1b7b1c
Binary files /dev/null and b/img/jira_mark_16px.png differ
diff --git a/img/jira_mark_white_16px.png b/img/jira_mark_white_16px.png
new file mode 100644
index 000000000..721600c13
Binary files /dev/null and b/img/jira_mark_white_16px.png differ
diff --git a/img/slack_mark_16px.png b/img/slack_mark_16px.png
new file mode 100644
index 000000000..13afbc596
Binary files /dev/null and b/img/slack_mark_16px.png differ
diff --git a/img/slack_mark_white_16px.png b/img/slack_mark_white_16px.png
new file mode 100644
index 000000000..cc739599d
Binary files /dev/null and b/img/slack_mark_white_16px.png differ
diff --git a/img/twitter_mark_16px.png b/img/twitter_mark_16px.png
new file mode 100644
index 000000000..bed6f4385
Binary files /dev/null and b/img/twitter_mark_16px.png differ
diff --git a/img/twitter_mark_white_16px.png b/img/twitter_mark_white_16px.png
new file mode 100644
index 000000000..bca2350c2
Binary files /dev/null and b/img/twitter_mark_white_16px.png differ
diff --git a/js/anchor.js b/js/anchor.js
new file mode 100644
index 000000000..e470643e6
--- /dev/null
+++ b/js/anchor.js
@@ -0,0 +1,322 @@
+/**
+ * AnchorJS - v3.1.0 - 2016-02-12
+ * https://github.com/bryanbraun/anchorjs
+ * Copyright (c) 2016 Bryan Braun; Licensed MIT
+ */
+
+function AnchorJS(options) {
+  'use strict';
+  this.options = options || {};
+  this.elements = [];
+
+  /**
+   * Assigns options to the internal options object, and provides defaults.
+   * @param {Object} opts - Options object
+   */
+  function _applyRemainingDefaultOptions(opts) {
+    opts.icon = opts.hasOwnProperty('icon') ? opts.icon : '\ue9cb'; // Accepts characters (and also URLs?), like  '#', '¶', '❡', or '§'.
+    opts.visible = opts.hasOwnProperty('visible') ? opts.visible : 'hover'; // Also accepts 'always' & 'touch'
+    opts.placement = opts.hasOwnProperty('placement') ? opts.placement : 'right'; // Also accepts 'left'
+    opts.class = opts.hasOwnProperty('class') ? opts.class : ''; // Accepts any class name.
+    // Using Math.floor here will ensure the value is Number-cast and an integer.
+    opts.truncate = opts.hasOwnProperty('truncate') ? Math.floor(opts.truncate) : 64; // Accepts any value that can be typecast to a number.
+  }
+
+  _applyRemainingDefaultOptions(this.options);
+
+  /**
+   * Checks to see if this device supports touch. Uses criteria pulled from Modernizr:
+   * https://github.com/Modernizr/Modernizr/blob/da22eb27631fc4957f67607fe6042e85c0a84656/feature-detects/touchevents.js#L40
+   * @return {Boolean} - true if the current device supports touch.
+   */
+  this.isTouchDevice = function() {
+    return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);
+  };
+
+  /**
+   * Add anchor links to page elements.
+   * @param  {String|Array|Nodelist} selector - A CSS selector for targeting the elements you wish to add anchor links
+   *                                            to. Also accepts an array or nodeList containing the relavant elements.
+   * @return {this}                           - The AnchorJS object
+   */
+  this.add = function(selector) {
+    var elements,
+        elsWithIds,
+        idList,
+        elementID,
+        i,
+        index,
+        count,
+        tidyText,
+        newTidyText,
+        readableID,
+        anchor,
+        visibleOptionToUse,
+        indexesToDrop = [];
+
+    // We reapply options here because somebody may have overwritten the default options object when setting options.
+    // For example, this overwrites all options but visible:
+    //
+    // anchors.options = { visible: 'always'; }
+    _applyRemainingDefaultOptions(this.options);
+
+    visibleOptionToUse = this.options.visible;
+    if (visibleOptionToUse === 'touch') {
+      visibleOptionToUse = this.isTouchDevice() ? 'always' : 'hover';
+    }
+
+    // Provide a sensible default selector, if none is given.
+    if (!selector) {
+      selector = 'h1, h2, h3, h4, h5, h6';
+    }
+
+    elements = _getElements(selector);
+
+    if (elements.length === 0) {
+      return false;
+    }
+
+    _addBaselineStyles();
+
+    // We produce a list of existing IDs so we don't generate a duplicate.
+    elsWithIds = document.querySelectorAll('[id]');
+    idList = [].map.call(elsWithIds, function assign(el) {
+      return el.id;
+    });
+
+    for (i = 0; i < elements.length; i++) {
+      if (this.hasAnchorJSLink(elements[i])) {
+        indexesToDrop.push(i);
+        continue;
+      }
+
+      if (elements[i].hasAttribute('id')) {
+        elementID = elements[i].getAttribute('id');
+      } else {
+        tidyText = this.urlify(elements[i].textContent);
+
+        // Compare our generated ID to existing IDs (and increment it if needed)
+        // before we add it to the page.
+        newTidyText = tidyText;
+        count = 0;
+        do {
+          if (index !== undefined) {
+            newTidyText = tidyText + '-' + count;
+          }
+
+          index = idList.indexOf(newTidyText);
+          count += 1;
+        } while (index !== -1);
+        index = undefined;
+        idList.push(newTidyText);
+
+        elements[i].setAttribute('id', newTidyText);
+        elementID = newTidyText;
+      }
+
+      readableID = elementID.replace(/-/g, ' ');
+
+      // The following code builds the following DOM structure in a more effiecient (albeit opaque) way.
+      // '<a class="anchorjs-link ' + this.options.class + '" href="#' + elementID + '" aria-label="Anchor link for: ' + readableID + '" data-anchorjs-icon="' + this.options.icon + '"></a>';
+      anchor = document.createElement('a');
+      anchor.className = 'anchorjs-link ' + this.options.class;
+      anchor.href = '#' + elementID;
+      anchor.setAttribute('aria-label', 'Anchor link for: ' + readableID);
+      anchor.setAttribute('data-anchorjs-icon', this.options.icon);
+
+      if (visibleOptionToUse === 'always') {
+        anchor.style.opacity = '1';
+      }
+
+      if (this.options.icon === '\ue9cb') {
+        anchor.style.fontFamily = 'anchorjs-icons';
+        anchor.style.fontStyle = 'normal';
+        anchor.style.fontVariant = 'normal';
+        anchor.style.fontWeight = 'normal';
+        anchor.style.lineHeight = 1;
+
+        // We set lineHeight = 1 here because the `anchorjs-icons` font family could otherwise affect the
+        // height of the heading. This isn't the case for icons with `placement: left`, so we restore
+        // line-height: inherit in that case, ensuring they remain positioned correctly. For more info,
+        // see https://github.com/bryanbraun/anchorjs/issues/39.
+        if (this.options.placement === 'left') {
+          anchor.style.lineHeight = 'inherit';
+        }
+      }
+
+      if (this.options.placement === 'left') {
+        anchor.style.position = 'absolute';
+        anchor.style.marginLeft = '-1em';
+        anchor.style.paddingRight = '0.5em';
+        elements[i].insertBefore(anchor, elements[i].firstChild);
+      } else { // if the option provided is `right` (or anything else).
+        anchor.style.paddingLeft = '0.375em';
+        elements[i].appendChild(anchor);
+      }
+    }
+
+    for (i = 0; i < indexesToDrop.length; i++) {
+      elements.splice(indexesToDrop[i] - i, 1);
+    }
+    this.elements = this.elements.concat(elements);
+
+    return this;
+  };
+
+  /**
+   * Removes all anchorjs-links from elements targed by the selector.
+   * @param  {String|Array|Nodelist} selector - A CSS selector string targeting elements with anchor links,
+   *                                       	  	OR a nodeList / array containing the DOM elements.
+   * @return {this}                           - The AnchorJS object
+   */
+  this.remove = function(selector) {
+    var index,
+        domAnchor,
+        elements = _getElements(selector);
+
+    for (var i = 0; i < elements.length; i++) {
+      domAnchor = elements[i].querySelector('.anchorjs-link');
+      if (domAnchor) {
+        // Drop the element from our main list, if it's in there.
+        index = this.elements.indexOf(elements[i]);
+        if (index !== -1) {
+          this.elements.splice(index, 1);
+        }
+        // Remove the anchor from the DOM.
+        elements[i].removeChild(domAnchor);
+      }
+    }
+    return this;
+  };
+
+  /**
+   * Removes all anchorjs links. Mostly used for tests.
+   */
+  this.removeAll = function() {
+    this.remove(this.elements);
+  };
+
+  /**
+   * Urlify - Refine text so it makes a good ID.
+   *
+   * To do this, we remove apostrophes, replace nonsafe characters with hyphens,
+   * remove extra hyphens, truncate, trim hyphens, and make lowercase.
+   *
+   * @param  {String} text - Any text. Usually pulled from the webpage element we are linking to.
+   * @return {String}      - hyphen-delimited text for use in IDs and URLs.
+   */
+  this.urlify = function(text) {
+    // Regex for finding the nonsafe URL characters (many need escaping): & +$,:;=?@"#{}|^~[`%!']./()*\
+    var nonsafeChars = /[& +$,:;=?@"#{}|^~[`%!'\]\.\/\(\)\*\\]/g,
+        urlText;
+
+    // The reason we include this _applyRemainingDefaultOptions is so urlify can be called independently,
+    // even after setting options. This can be useful for tests or other applications.
+    if (!this.options.truncate) {
+      _applyRemainingDefaultOptions(this.options);
+    }
+
+    // Note: we trim hyphens after truncating because truncating can cause dangling hyphens.
+    // Example string:                                  // " ⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
+    urlText = text.trim()                               // "⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
+                  .replace(/\'/gi, '')                  // "⚡⚡ Dont forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
+                  .replace(nonsafeChars, '-')           // "⚡⚡-Dont-forget--URL-fragments-should-be-i18n-friendly--hyphenated--short--and-clean-"
+                  .replace(/-{2,}/g, '-')               // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-short-and-clean-"
+                  .substring(0, this.options.truncate)  // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-"
+                  .replace(/^-+|-+$/gm, '')             // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated"
+                  .toLowerCase();                       // "⚡⚡-dont-forget-url-fragments-should-be-i18n-friendly-hyphenated"
+
+    return urlText;
+  };
+
+  /**
+   * Determines if this element already has an AnchorJS link on it.
+   * Uses this technique: http://stackoverflow.com/a/5898748/1154642
+   * @param    {HTMLElemnt}  el - a DOM node
+   * @return   {Boolean}     true/false
+   */
+  this.hasAnchorJSLink = function(el) {
+    var hasLeftAnchor = (' ' + el.firstChild.className + ' ').indexOf(' anchorjs-link ') > -1,
+        hasRightAnchor = (' ' + el.lastChild.className + ' ').indexOf(' anchorjs-link ') > -1;
+
+    return hasLeftAnchor || hasRightAnchor;
+  };
+
+  /**
+   * Turns a selector, nodeList, or array of elements into an array of elements (so we can use array methods).
+   * It also throws errors on any other inputs. Used to handle inputs to .add and .remove.
+   * @param  {String|Array|Nodelist} input - A CSS selector string targeting elements with anchor links,
+   *                                       	 OR a nodeList / array containing the DOM elements.
+   * @return {Array} - An array containing the elements we want.
+   */
+  function _getElements(input) {
+    var elements;
+    if (typeof input === 'string' || input instanceof String) {
+      // See https://davidwalsh.name/nodelist-array for the technique transforming nodeList -> Array.
+      elements = [].slice.call(document.querySelectorAll(input));
+    // I checked the 'input instanceof NodeList' test in IE9 and modern browsers and it worked for me.
+    } else if (Array.isArray(input) || input instanceof NodeList) {
+      elements = [].slice.call(input);
+    } else {
+      throw new Error('The selector provided to AnchorJS was invalid.');
+    }
+    return elements;
+  }
+
+  /**
+   * _addBaselineStyles
+   * Adds baseline styles to the page, used by all AnchorJS links irregardless of configuration.
+   */
+  function _addBaselineStyles() {
+    // We don't want to add global baseline styles if they've been added before.
+    if (document.head.querySelector('style.anchorjs') !== null) {
+      return;
+    }
+
+    var style = document.createElement('style'),
+        linkRule =
+        ' .anchorjs-link {'                       +
+        '   opacity: 0;'                          +
+        '   text-decoration: none;'               +
+        '   -webkit-font-smoothing: antialiased;' +
+        '   -moz-osx-font-smoothing: grayscale;'  +
+        ' }',
+        hoverRule =
+        ' *:hover > .anchorjs-link,'              +
+        ' .anchorjs-link:focus  {'                +
+        '   opacity: 1;'                          +
+        ' }',
+        anchorjsLinkFontFace =
+        ' @font-face {'                           +
+        '   font-family: "anchorjs-icons";'       +
+        '   font-style: normal;'                  +
+        '   font-weight: normal;'                 + // Icon from icomoon; 10px wide & 10px tall; 2 empty below & 4 above
+        '   src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBTUAAAC8AAAAYGNtYXAWi9QdAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5Zgq29TcAAAF4AAABNGhlYWQEZM3pAAACrAAAADZoaGVhBhUDxgAAAuQAAAAkaG10eASAADEAAAMIAAAAFGxvY2EAKACuAAADHAAAAAxtYXhwAAgAVwAAAygAAAAgbmFtZQ5yJ3cAAANIAAAB2nBvc3QAAwAAAAAFJAAAACAAAwJAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADpywPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOA [...]
+        ' }',
+        pseudoElContent =
+        ' [data-anchorjs-icon]::after {'          +
+        '   content: attr(data-anchorjs-icon);'   +
+        ' }',
+        firstStyleEl;
+
+    style.className = 'anchorjs';
+    style.appendChild(document.createTextNode('')); // Necessary for Webkit.
+
+    // We place it in the head with the other style tags, if possible, so as to
+    // not look out of place. We insert before the others so these styles can be
+    // overridden if necessary.
+    firstStyleEl = document.head.querySelector('[rel="stylesheet"], style');
+    if (firstStyleEl === undefined) {
+      document.head.appendChild(style);
+    } else {
+      document.head.insertBefore(style, firstStyleEl);
+    }
+
+    style.sheet.insertRule(linkRule, style.sheet.cssRules.length);
+    style.sheet.insertRule(hoverRule, style.sheet.cssRules.length);
+    style.sheet.insertRule(pseudoElContent, style.sheet.cssRules.length);
+    style.sheet.insertRule(anchorjsLinkFontFace, style.sheet.cssRules.length);
+  }
+}
+
+var anchors = new AnchorJS();
diff --git a/js/bootstrap.min.js b/js/bootstrap.min.js
new file mode 100644
index 000000000..e79c06513
--- /dev/null
+++ b/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:" [...]
+d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data()) [...]
\ No newline at end of file
diff --git a/js/jquery.min.js b/js/jquery.min.js
new file mode 100644
index 000000000..f3644431e
--- /dev/null
+++ b/js/jquery.min.js
@@ -0,0 +1,6 @@
+/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b [...]
+
+return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}fu [...]
+return new Za.prototype.init(a,b,c,d,e)}m.Tween=Za,Za.prototype={constructor:Za,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")},cur:function(){var a=Za.propHooks[this.prop];return a&&a.get?a.get(this):Za.propHooks._default.get(this)},run:function(a){var b,c=Za.propHooks[this.prop];return this.options.duration?this.pos=b=m.easing[this.easing](a,this.options.duration*a, [...]
+//# sourceMappingURL=jquery.min.map
\ No newline at end of file
diff --git a/site_tool b/site_tool
index d251b1d02..ca7c08f05 100755
--- a/site_tool
+++ b/site_tool
@@ -122,8 +122,7 @@ def proof(args):
     eprint("Could not build site!")
     return 1
   return subprocess.call(
-    [BUNDLE_PATH, "exec", 'htmlproof',
-     '--verbose',
+    [BUNDLE_PATH, "exec", 'htmlproofer',
      # Dont check the javadocs, old doc versions, or the configuration
      # reference files which are extremely large.
      '--file-ignore', '/apidocs|releases|configuration_ref|cpp-client-api/',