summaryrefslogtreecommitdiff
path: root/static/website/bootstrap-css/bower_components/smooth-scroll
diff options
context:
space:
mode:
Diffstat (limited to 'static/website/bootstrap-css/bower_components/smooth-scroll')
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/.bower.json15
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/.gitignore10
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/.travis.yml6
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/LICENSE.md21
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/README.md259
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/buoy.js337
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/buoy.min.js2
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/smooth-scroll.js484
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/smooth-scroll.min.js2
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/docs/assets/css/custom.css20
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/buoy.js337
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/buoy.min.js2
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/smooth-scroll.js484
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/smooth-scroll.min.js2
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/docs/index.html86
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/gulpfile.js297
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/index.html86
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/package.json48
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/_templates/_footer.html20
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/_templates/_header.html23
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/assets/css/custom.css20
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/index.html44
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/src/js/buoy.js328
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/src/js/smooth-scroll.js475
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/test/karma.conf.js26
-rw-r--r--static/website/bootstrap-css/bower_components/smooth-scroll/test/spec/spec-smoothScroll.js131
26 files changed, 3565 insertions, 0 deletions
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/.bower.json b/static/website/bootstrap-css/bower_components/smooth-scroll/.bower.json
new file mode 100644
index 0000000..5d375a5
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/.bower.json
@@ -0,0 +1,15 @@
+{
+ "name": "smooth-scroll",
+ "homepage": "https://github.com/cferdinandi/smooth-scroll",
+ "version": "7.0.0",
+ "_release": "7.0.0",
+ "_resolution": {
+ "type": "version",
+ "tag": "v7.0.0",
+ "commit": "5c3a07adb4e692d652611eb137a653ff1c060b93"
+ },
+ "_source": "https://github.com/cferdinandi/smooth-scroll.git",
+ "_target": "~7.0.0",
+ "_originalSource": "https://github.com/cferdinandi/smooth-scroll.git",
+ "_direct": true
+} \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/.gitignore b/static/website/bootstrap-css/bower_components/smooth-scroll/.gitignore
new file mode 100644
index 0000000..62fb128
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/.gitignore
@@ -0,0 +1,10 @@
+# Node
+node_modules
+test/results
+test/coverage
+
+## OS X
+.DS_Store
+._*
+.Spotlight-V100
+.Trashes \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/.travis.yml b/static/website/bootstrap-css/bower_components/smooth-scroll/.travis.yml
new file mode 100644
index 0000000..83be3c0
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+node_js:
+ - "0.10"
+before_script:
+ - npm install -g gulp
+script: gulp \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/LICENSE.md b/static/website/bootstrap-css/bower_components/smooth-scroll/LICENSE.md
new file mode 100644
index 0000000..b5e8ef7
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/LICENSE.md
@@ -0,0 +1,21 @@
+# The MIT License (MIT)
+
+Copyright (c) Go Make Things, LLC
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/README.md b/static/website/bootstrap-css/bower_components/smooth-scroll/README.md
new file mode 100644
index 0000000..bbebf0e
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/README.md
@@ -0,0 +1,259 @@
+# Smooth Scroll [![Build Status](https://travis-ci.org/cferdinandi/smooth-scroll.svg)](https://travis-ci.org/cferdinandi/smooth-scroll)
+A lightweight script to animate scrolling to anchor links. Smooth Scroll works great with [Gumshoe](https://github.com/cferdinandi/gumshoe).
+
+[Download Smooth Scroll](https://github.com/cferdinandi/smooth-scroll/archive/master.zip) / [View the demo](http://cferdinandi.github.io/smooth-scroll/)
+
+**In This Documentation**
+
+1. [Getting Started](#getting-started)
+2. [Installing with Package Managers](#installing-with-package-managers)
+3. [Working with the Source Files](#working-with-the-source-files)
+4. [Options & Settings](#options-and-settings)
+5. [Browser Compatibility](#browser-compatibility)
+6. [Known Issues](#known-issues)
+7. [How to Contribute](#how-to-contribute)
+8. [License](#license)
+
+
+
+## Getting Started
+
+Compiled and production-ready code can be found in the `dist` directory. The `src` directory contains development code. Unit tests are located in the `test` directory.
+
+### 1. Include Smooth Scroll on your site.
+
+```html
+<script src="dist/js/smooth-scroll.js"></script>
+```
+
+### 2. Add the markup to your HTML.
+
+```html
+<a data-scroll href="#bazinga">Anchor Link</a>
+...
+<span id="bazinga">Bazinga!</span>
+```
+
+Turn anchor links into Smooth Scroll links by adding the `[data-scroll]` data attribute. Give the anchor location an ID just like you normally would.
+
+### 3. Initialize Smooth Scroll.
+
+```html
+<script>
+ smoothScroll.init();
+</script>
+```
+
+In the footer of your page, after the content, initialize Smooth Scroll. And that's it, you're done. Nice work!
+
+
+
+## Installing with Package Managers
+
+You can install Smooth Scroll with your favorite package manager.
+
+* **[NPM](https://www.npmjs.org/):** `npm install cferdinandi/smooth-scroll`
+* **[Bower](http://bower.io/):** `bower install https://github.com/cferdinandi/smooth-scroll.git`
+* **[Component](http://component.io/):** `component install cferdinandi/smooth-scroll`
+
+
+
+## Working with the Source Files
+
+If you would prefer, you can work with the development code in the `src` directory using the included [Gulp build system](http://gulpjs.com/). This compiles, lints, and minifies code, and runs unit tests. It's the same build system that's used by [Kraken](http://cferdinandi.github.io/kraken/), so it includes some unnecessary tasks and Sass variables but can be dropped right in to the boilerplate without any configuration.
+
+### Dependencies
+Make sure these are installed first.
+
+* [Node.js](http://nodejs.org)
+* [Gulp](http://gulpjs.com) `sudo npm install -g gulp`
+
+### Quick Start
+
+1. In bash/terminal/command line, `cd` into your project directory.
+2. Run `npm install` to install required files.
+3. When it's done installing, run one of the task runners to get going:
+ * `gulp` manually compiles files.
+ * `gulp watch` automatically compiles files when changes are made and applies changes using [LiveReload](http://livereload.com/).
+
+
+
+## Options and Settings
+
+Smooth Scroll includes smart defaults and works right out of the box. But if you want to customize things, it also has a robust API that provides multiple ways for you to adjust the default options and settings.
+
+### Global Settings
+
+You can pass options and callbacks into Smooth Scroll through the `init()` function:
+
+```javascript
+smoothScroll.init({
+ speed: 500, // Integer. How fast to complete the scroll in milliseconds
+ easing: 'easeInOutCubic', // Easing pattern to use
+ updateURL: true, // Boolean. Whether or not to update the URL with the anchor hash on scroll
+ offset: 0, // Integer. How far to offset the scrolling anchor location in pixels
+ callback: function ( toggle, anchor ) {} // Function to run after scrolling
+});
+```
+
+#### Easing Options
+
+**Linear**
+*Moves at the same speed from start to finish.*
+
+* `Linear`
+
+
+**Ease-In**
+*Gradually increases in speed.*
+
+* `easeInQuad`
+* `easeInCubic`
+* `easeInQuart`
+* `easeInQuint`
+
+
+**Ease-In-Out**
+*Gradually increases in speed, peaks, and then gradually slows down.*
+
+* `easeInOutQuad`
+* `easeInOutCubic`
+* `easeInOutQuart`
+* `easeInOutQuint`
+
+
+**Ease-Out**
+*Gradually decreases in speed.*
+
+* `easeOutQuad`
+* `easeOutCubic`
+* `easeOutQuart`
+* `easeOutQuint`
+
+
+Learn more about the different easing patterns and what they do at [easings.net](http://easings.net/).
+
+### Override settings with data attributes
+
+Smooth Scroll also lets you override global settings on a link-by-link basis using the `[data-options]` data attribute:
+
+```html
+<a data-scroll
+ data-options='{
+ "speed": 500,
+ "easing": "easeInOutCubic",
+ "offset": 0,
+ "updateURL": false
+ }'
+>
+ Anchor Link
+</a>
+```
+
+**Note:** You must use [valid JSON](http://jsonlint.com/) in order for the `data-options` feature to work.
+
+### Use Smooth Scroll events in your own scripts
+
+You can also call Smooth Scroll's scroll animation events in your own scripts.
+
+#### animateScroll()
+Animate scrolling to an anchor.
+
+```javascript
+smoothScroll.animateScroll(
+ toggle, // Node that toggles the animation. ex. document.querySelector('#toggle')
+ anchor, // ID of the anchor to scroll to. ex. '#bazinga'
+ options // Classes and callbacks. Same options as those passed into the init() function.
+);
+```
+
+**Example 1**
+
+```javascript
+smoothScroll.animateScroll( null, '#bazinga' );
+```
+
+**Example 2**
+
+```javascript
+var toggle = document.querySelector('#toggle');
+var options = { speed: 1000, easing: 'easeOutCubic' };
+smoothScroll.animateScroll( toggle, '#bazinga', options );
+```
+
+#### destroy()
+Destroy the current `smoothScroll.init()`. This is called automatically during the `init` function to remove any existing initializations.
+
+```javascript
+smoothScroll.destroy();
+```
+
+
+### Fixed Headers
+
+Add a `[data-scroll-header]` data attribute to fixed headers. Smooth Scroll will automatically offset scroll distances by the header height. If you have multiple fixed headers, add `[data-scroll-header]` to the last one in the markup.
+
+```html
+<nav data-scroll-header>
+ ...
+</nav>
+```
+
+### Animating links to other pages
+
+Smooth Scroll does not include an option to animate scrolling to links on other pages, but you can easily add this functionality using the API.
+
+1. Do *not* add the `data-scroll` attribute to links to other pages. Treat them like normal links, and include your anchor link hash as normal.
+ ```markup
+ <a href="some-page.html#example">
+ ```
+2. Add the following script to the footer of your page, after the `smoothScroll.init()` function.
+ ```markup
+ <script>
+ if ( window.location.hash ) {
+ var options = {}; // Any custom options you want to use would go here
+ smoothScroll.animateScroll( null, window.location.hash, options );
+ }
+ </script>
+ ```
+
+
+## Browser Compatibility
+
+Smooth Scroll works in all modern browsers, and IE 9 and above.
+
+Smooth Scroll is built with modern JavaScript APIs, and uses progressive enhancement. If the JavaScript file fails to load, or if your site is viewed on older and less capable browsers, anchor links will jump the way they normally would. If you need to smooth scrolling for older browsers, [download the jQuery version of Smooth Scroll on GitHub](https://github.com/cferdinandi/smooth-scroll/tree/archive-v1).
+
+
+
+## Known Issues
+
+If the `<body>` element has been assigned a height of `100%`, Smooth Scroll is unable to properly calculate page distances and will not scroll to the right location. The `<body>` element can have a fixed, non-percentage based height (ex. `500px`), or a height of `auto`.
+
+
+
+## Adding `[data-scroll]` attributes to the `wp_nav_menu()` in WordPress
+
+Add this to your `functions.php` file:
+
+```js
+function YOURPREFIX_custom_nav_attributes ( $atts, $item, $args ) {
+ $atts['data-scroll'] = 'true';
+ return $atts;
+}
+add_filter( 'nav_menu_link_attributes', 'YOURPREFIX_custom_nav_attributes', 10, 3 );
+```
+
+**Source:** http://wordpress.stackexchange.com/questions/121123/how-to-add-a-data-attribute-to-a-wordpress-menu-item
+
+
+
+## How to Contribute
+
+In lieu of a formal style guide, take care to maintain the existing coding style. Please apply fixes to both the development and production code. Don't forget to update the version number, and when applicable, the documentation.
+
+
+
+## License
+
+The code is available under the [MIT License](LICENSE.md). \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/buoy.js b/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/buoy.js
new file mode 100644
index 0000000..ea39a59
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/buoy.js
@@ -0,0 +1,337 @@
+/**
+ * smooth-scroll v7.0.0
+ * Animate scrolling to anchor links, by Chris Ferdinandi.
+ * http://github.com/cferdinandi/smooth-scroll
+ *
+ * Free to use under the MIT License.
+ * http://gomakethings.com/mit/
+ */
+
+(function (root, factory) {
+ if ( typeof define === 'function' && define.amd ) {
+ define([], factory(root));
+ } else if ( typeof exports === 'object' ) {
+ module.exports = factory(root);
+ } else {
+ root.buoy = factory(root);
+ }
+})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
+
+ 'use strict';
+
+ // Object for public APIs
+ var buoy = {};
+
+
+ //
+ // Methods
+ //
+
+ /**
+ * Wait until the DOM is ready before executing code
+ * @param {Function} fn The function to execute when the DOM is ready
+ */
+ buoy.ready = function ( fn ) {
+
+ // Sanity check
+ if ( typeof fn !== 'function' ) return;
+
+ // If document is already loaded, run method
+ if ( document.readyState === 'complete' ) {
+ return fn();
+ }
+
+ // Otherwise, wait until document is loaded
+ document.addEventListener( 'DOMContentLoaded', fn, false );
+
+ };
+
+ /**
+ * A simple forEach() implementation for Arrays, Objects and NodeLists.
+ * @author Todd Motto
+ * @link https://github.com/toddmotto/foreach
+ * @param {Array|Object|NodeList} collection Collection of items to iterate
+ * @param {Function} callback Callback function for each iteration
+ * @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
+ */
+ buoy.forEach = function ( collection, callback, scope ) {
+ if ( Object.prototype.toString.call( collection ) === '[object Object]' ) {
+ for ( var prop in collection ) {
+ if ( Object.prototype.hasOwnProperty.call( collection, prop ) ) {
+ callback.call( scope, collection[prop], prop, collection );
+ }
+ }
+ } else {
+ for ( var i = 0, len = collection.length; i < len; i++ ) {
+ callback.call( scope, collection[i], i, collection );
+ }
+ }
+ };
+
+ /**
+ * Merge two or more objects. Returns a new object.
+ * @param {Boolean} deep If true, do a deep (or recursive) merge [optional]
+ * @param {Object} objects The objects to merge together
+ * @returns {Object} Merged values of defaults and options
+ */
+ buoy.extend = function () {
+
+ // Variables
+ var extended = {};
+ var deep = false;
+ var i = 0;
+ var length = arguments.length;
+
+ // Check if a deep merge
+ if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
+ deep = arguments[0];
+ i++;
+ }
+
+ // Merge the object into the extended object
+ var merge = function (obj) {
+ for ( var prop in obj ) {
+ if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
+ // If deep merge and property is an object, merge properties
+ if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
+ extended[prop] = buoy.extend( true, extended[prop], obj[prop] );
+ } else {
+ extended[prop] = obj[prop];
+ }
+ }
+ }
+ };
+
+ // Loop through each object and conduct a merge
+ for ( ; i < length; i++ ) {
+ var obj = arguments[i];
+ merge(obj);
+ }
+
+ return extended;
+
+ };
+
+ /**
+ * Get the height of an element.
+ * @param {Node} elem The element to get the height of
+ * @return {Number} The element's height in pixels
+ */
+ buoy.getHeight = function ( elem ) {
+ return Math.max( elem.scrollHeight, elem.offsetHeight, elem.clientHeight );
+ };
+
+ /**
+ * Get an element's distance from the top of the Document.
+ * @param {Node} elem The element
+ * @return {Number} Distance from the top in pixels
+ */
+ buoy.getOffsetTop = function ( elem ) {
+ var location = 0;
+ if (elem.offsetParent) {
+ do {
+ location += elem.offsetTop;
+ elem = elem.offsetParent;
+ } while (elem);
+ }
+ return location >= 0 ? location : 0;
+ };
+
+ /**
+ * Get the closest matching element up the DOM tree.
+ * @param {Element} elem Starting element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Boolean|Element} Returns null if not match found
+ */
+ buoy.getClosest = function ( elem, selector ) {
+
+ // Variables
+ var firstChar = selector.charAt(0);
+ var supports = 'classList' in document.documentElement;
+ var attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+
+ // Get closest match
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ return elem;
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ return elem;
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ return elem;
+ }
+ } else {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ return elem;
+ }
+
+ }
+
+ return null;
+
+ };
+
+ /**
+ * Get an element's parents.
+ * @param {Node} elem The element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Array} An array of matching nodes
+ */
+ buoy.getParents = function ( elem, selector ) {
+
+ // Variables
+ var parents = [];
+ var supports = 'classList' in document.documentElement;
+ var firstChar, attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( selector ) {
+ firstChar = selector.charAt(0);
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+ }
+
+ // Get matches
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+ if ( selector ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ parents.push( elem );
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ parents.push( elem );
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ parents.push( elem );
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ parents.push( elem );
+ }
+ } else {
+ parents.push( elem );
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ parents.push( elem );
+ }
+
+ } else {
+ parents.push( elem );
+ }
+
+ }
+
+ // Return parents if any exist
+ if ( parents.length === 0 ) {
+ return null;
+ } else {
+ return parents;
+ }
+
+ };
+
+ /**
+ * Get an element's siblings.
+ * @param {Node} elem The element
+ * @return {Array} An array of sibling nodes
+ */
+ buoy.getSiblings = function ( elem ) {
+
+ // Variables
+ var siblings = [];
+ var sibling = elem.parentNode.firstChild;
+
+ // Loop through all sibling nodes
+ for ( ; sibling; sibling = sibling.nextSibling ) {
+ if ( sibling.nodeType === 1 && sibling !== elem ) {
+ siblings.push( sibling );
+ }
+ }
+
+ return siblings;
+
+ };
+
+ /**
+ * Get data from a URL query string.
+ * @param {String} field The field to get from the URL
+ * @param {String} url The URL to parse
+ * @return {String} The field value
+ */
+ buoy.getQueryString = function ( field, url ) {
+ var href = url ? url : window.location.href;
+ var reg = new RegExp( '[?&]' + field + '=([^&#]*)', 'i' );
+ var string = reg.exec(href);
+ return string ? string[1] : null;
+ };
+
+
+ //
+ // Public APIs
+ //
+
+ return buoy;
+
+}); \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/buoy.min.js b/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/buoy.min.js
new file mode 100644
index 0000000..fb59080
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/buoy.min.js
@@ -0,0 +1,2 @@
+/** smooth-scroll v7.0.0, by Chris Ferdinandi | http://github.com/cferdinandi/smooth-scroll | Licensed under MIT: http://gomakethings.com/mit/ */
+!function(t,e){"function"==typeof define&&define.amd?define([],e(t)):"object"==typeof exports?module.exports=e(t):t.buoy=e(t)}("undefined"!=typeof global?global:this.window||this.global,function(t){"use strict";var e={};return e.ready=function(t){return"function"==typeof t?"complete"===document.readyState?t():void document.addEventListener("DOMContentLoaded",t,!1):void 0},e.forEach=function(t,e,n){if("[object Object]"===Object.prototype.toString.call(t))for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&e.call(n,t[r],r,t);else for(var o=0,s=t.length;s>o;o++)e.call(n,t[o],o,t)},e.extend=function(){var t={},n=!1,r=0,o=arguments.length;"[object Boolean]"===Object.prototype.toString.call(arguments[0])&&(n=arguments[0],r++);for(var s=function(r){for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(t[o]=n&&"[object Object]"===Object.prototype.toString.call(r[o])?e.extend(!0,t[o],r[o]):r[o])};o>r;r++){var i=arguments[r];s(i)}return t},e.getHeight=function(t){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},e.getOffsetTop=function(t){var e=0;if(t.offsetParent)do e+=t.offsetTop,t=t.offsetParent;while(t);return e>=0?e:0},e.getClosest=function(t,e){var n,r,o=e.charAt(0),s="classList"in document.documentElement;for("["===o&&(e=e.substr(1,e.length-2),n=e.split("="),n.length>1&&(r=!0,n[1]=n[1].replace(/"/g,"").replace(/'/g,"")));t&&t!==document;t=t.parentNode){if("."===o)if(s){if(t.classList.contains(e.substr(1)))return t}else if(new RegExp("(^|\\s)"+e.substr(1)+"(\\s|$)").test(t.className))return t;if("#"===o&&t.id===e.substr(1))return t;if("["===o&&t.hasAttribute(n[0])){if(!r)return t;if(t.getAttribute(n[0])===n[1])return t}if(t.tagName.toLowerCase()===e)return t}return null},e.getParents=function(t,e){var n,r,o,s=[],i="classList"in document.documentElement;for(e&&(n=e.charAt(0),"["===n&&(e=e.substr(1,e.length-2),r=e.split("="),r.length>1&&(o=!0,r[1]=r[1].replace(/"/g,"").replace(/'/g,""))));t&&t!==document;t=t.parentNode)e?("."===n&&(i?t.classList.contains(e.substr(1))&&s.push(t):new RegExp("(^|\\s)"+e.substr(1)+"(\\s|$)").test(t.className)&&s.push(t)),"#"===n&&t.id===e.substr(1)&&s.push(t),"["===n&&t.hasAttribute(r[0])&&(o?t.getAttribute(r[0])===r[1]&&s.push(t):s.push(t)),t.tagName.toLowerCase()===e&&s.push(t)):s.push(t);return 0===s.length?null:s},e.getSiblings=function(t){for(var e=[],n=t.parentNode.firstChild;n;n=n.nextSibling)1===n.nodeType&&n!==t&&e.push(n);return e},e.getQueryString=function(t,e){var n=e?e:window.location.href,r=new RegExp("[?&]"+t+"=([^&#]*)","i"),o=r.exec(n);return o?o[1]:null},e}); \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/smooth-scroll.js b/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/smooth-scroll.js
new file mode 100644
index 0000000..3edd05d
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/smooth-scroll.js
@@ -0,0 +1,484 @@
+/**
+ * smooth-scroll v7.0.0
+ * Animate scrolling to anchor links, by Chris Ferdinandi.
+ * http://github.com/cferdinandi/smooth-scroll
+ *
+ * Free to use under the MIT License.
+ * http://gomakethings.com/mit/
+ */
+
+(function (root, factory) {
+ if ( typeof define === 'function' && define.amd ) {
+ define(['buoy'], factory(root));
+ } else if ( typeof exports === 'object' ) {
+ module.exports = factory(root, require('buoy'));
+ } else {
+ root.smoothScroll = factory(root, root.buoy);
+ }
+})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
+
+ 'use strict';
+
+ //
+ // Variables
+ //
+
+ var smoothScroll = {}; // Object for public APIs
+ var supports = !!root.document.querySelector && !!root.addEventListener; // Feature test
+ var settings, eventTimeout, fixedHeader, headerHeight;
+
+ // Default settings
+ var defaults = {
+ speed: 500,
+ easing: 'easeInOutCubic',
+ offset: 0,
+ updateURL: true,
+ callback: function () {}
+ };
+
+
+ //
+ // Methods
+ //
+
+ /**
+ * Merge two or more objects. Returns a new object.
+ * @private
+ * @param {Boolean} deep If true, do a deep (or recursive) merge [optional]
+ * @param {Object} objects The objects to merge together
+ * @returns {Object} Merged values of defaults and options
+ */
+ var extend = function () {
+
+ // Variables
+ var extended = {};
+ var deep = false;
+ var i = 0;
+ var length = arguments.length;
+
+ // Check if a deep merge
+ if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
+ deep = arguments[0];
+ i++;
+ }
+
+ // Merge the object into the extended object
+ var merge = function (obj) {
+ for ( var prop in obj ) {
+ if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
+ // If deep merge and property is an object, merge properties
+ if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
+ extended[prop] = extend( true, extended[prop], obj[prop] );
+ } else {
+ extended[prop] = obj[prop];
+ }
+ }
+ }
+ };
+
+ // Loop through each object and conduct a merge
+ for ( ; i < length; i++ ) {
+ var obj = arguments[i];
+ merge(obj);
+ }
+
+ return extended;
+
+ };
+
+ /**
+ * Get the height of an element.
+ * @private
+ * @param {Node} elem The element to get the height of
+ * @return {Number} The element's height in pixels
+ */
+ var getHeight = function ( elem ) {
+ return Math.max( elem.scrollHeight, elem.offsetHeight, elem.clientHeight );
+ };
+
+ /**
+ * Get the closest matching element up the DOM tree.
+ * @private
+ * @param {Element} elem Starting element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Boolean|Element} Returns null if not match found
+ */
+ var getClosest = function ( elem, selector ) {
+
+ // Variables
+ var firstChar = selector.charAt(0);
+ var supports = 'classList' in document.documentElement;
+ var attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+
+ // Get closest match
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ return elem;
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ return elem;
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ return elem;
+ }
+ } else {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ return elem;
+ }
+
+ }
+
+ return null;
+
+ };
+
+ /**
+ * Escape special characters for use with querySelector
+ * @private
+ * @param {String} id The anchor ID to escape
+ * @author Mathias Bynens
+ * @link https://github.com/mathiasbynens/CSS.escape
+ */
+ var escapeCharacters = function ( id ) {
+ var string = String(id);
+ var length = string.length;
+ var index = -1;
+ var codeUnit;
+ var result = '';
+ var firstCodeUnit = string.charCodeAt(0);
+ while (++index < length) {
+ codeUnit = string.charCodeAt(index);
+ // Note: there’s no need to special-case astral symbols, surrogate
+ // pairs, or lone surrogates.
+
+ // If the character is NULL (U+0000), then throw an
+ // `InvalidCharacterError` exception and terminate these steps.
+ if (codeUnit === 0x0000) {
+ throw new InvalidCharacterError(
+ 'Invalid character: the input contains U+0000.'
+ );
+ }
+
+ if (
+ // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
+ // U+007F, […]
+ (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
+ // If the character is the first character and is in the range [0-9]
+ // (U+0030 to U+0039), […]
+ (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
+ // If the character is the second character and is in the range [0-9]
+ // (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
+ (
+ index === 1 &&
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
+ firstCodeUnit === 0x002D
+ )
+ ) {
+ // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
+ result += '\\' + codeUnit.toString(16) + ' ';
+ continue;
+ }
+
+ // If the character is not handled by one of the above rules and is
+ // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
+ // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
+ // U+005A), or [a-z] (U+0061 to U+007A), […]
+ if (
+ codeUnit >= 0x0080 ||
+ codeUnit === 0x002D ||
+ codeUnit === 0x005F ||
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
+ codeUnit >= 0x0041 && codeUnit <= 0x005A ||
+ codeUnit >= 0x0061 && codeUnit <= 0x007A
+ ) {
+ // the character itself
+ result += string.charAt(index);
+ continue;
+ }
+
+ // Otherwise, the escaped character.
+ // http://dev.w3.org/csswg/cssom/#escape-a-character
+ result += '\\' + string.charAt(index);
+
+ }
+ return result;
+ };
+
+ /**
+ * Calculate the easing pattern
+ * @private
+ * @link https://gist.github.com/gre/1650294
+ * @param {String} type Easing pattern
+ * @param {Number} time Time animation should take to complete
+ * @returns {Number}
+ */
+ var easingPattern = function ( type, time ) {
+ var pattern;
+ if ( type === 'easeInQuad' ) pattern = time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuad' ) pattern = time * (2 - time); // decelerating to zero velocity
+ if ( type === 'easeInOutQuad' ) pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
+ if ( type === 'easeInCubic' ) pattern = time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutCubic' ) pattern = (--time) * time * time + 1; // decelerating to zero velocity
+ if ( type === 'easeInOutCubic' ) pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
+ if ( type === 'easeInQuart' ) pattern = time * time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuart' ) pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity
+ if ( type === 'easeInOutQuart' ) pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
+ if ( type === 'easeInQuint' ) pattern = time * time * time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuint' ) pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity
+ if ( type === 'easeInOutQuint' ) pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
+ return pattern || time; // no easing, no acceleration
+ };
+
+ /**
+ * Calculate how far to scroll
+ * @private
+ * @param {Element} anchor The anchor element to scroll to
+ * @param {Number} headerHeight Height of a fixed header, if any
+ * @param {Number} offset Number of pixels by which to offset scroll
+ * @returns {Number}
+ */
+ var getEndLocation = function ( anchor, headerHeight, offset ) {
+ var location = 0;
+ if (anchor.offsetParent) {
+ do {
+ location += anchor.offsetTop;
+ anchor = anchor.offsetParent;
+ } while (anchor);
+ }
+ location = location - headerHeight - offset;
+ return location >= 0 ? location : 0;
+ };
+
+ /**
+ * Determine the document's height
+ * @private
+ * @returns {Number}
+ */
+ var getDocumentHeight = function () {
+ return Math.max(
+ root.document.body.scrollHeight, root.document.documentElement.scrollHeight,
+ root.document.body.offsetHeight, root.document.documentElement.offsetHeight,
+ root.document.body.clientHeight, root.document.documentElement.clientHeight
+ );
+ };
+
+ /**
+ * Convert data-options attribute into an object of key/value pairs
+ * @private
+ * @param {String} options Link-specific options as a data attribute string
+ * @returns {Object}
+ */
+ var getDataOptions = function ( options ) {
+ return !options || !(typeof JSON === 'object' && typeof JSON.parse === 'function') ? {} : JSON.parse( options );
+ };
+
+ /**
+ * Update the URL
+ * @private
+ * @param {Element} anchor The element to scroll to
+ * @param {Boolean} url Whether or not to update the URL history
+ */
+ var updateUrl = function ( anchor, url ) {
+ if ( root.history.pushState && (url || url === 'true') ) {
+ root.history.pushState( null, null, [root.location.protocol, '//', root.location.host, root.location.pathname, root.location.search, anchor].join('') );
+ }
+ };
+
+ var getHeaderHeight = function ( header ) {
+ return header === null ? 0 : ( getHeight( header ) + header.offsetTop );
+ };
+
+ /**
+ * Start/stop the scrolling animation
+ * @public
+ * @param {Element} toggle The element that toggled the scroll event
+ * @param {Element} anchor The element to scroll to
+ * @param {Object} options
+ */
+ smoothScroll.animateScroll = function ( toggle, anchor, options ) {
+
+ // Options and overrides
+ var overrides = getDataOptions( toggle ? toggle.getAttribute('data-options') : null );
+ var settings = extend( settings || defaults, options || {}, overrides ); // Merge user options with defaults
+ anchor = '#' + escapeCharacters(anchor.substr(1)); // Escape special characters and leading numbers
+
+ // Selectors and variables
+ var anchorElem = anchor === '#' ? root.document.documentElement : root.document.querySelector(anchor);
+ var startLocation = root.pageYOffset; // Current location on the page
+ if ( !fixedHeader ) { fixedHeader = root.document.querySelector('[data-scroll-header]'); } // Get the fixed header if not already set
+ if ( !headerHeight ) { headerHeight = getHeaderHeight( fixedHeader ); } // Get the height of a fixed header if one exists and not already set
+ var endLocation = getEndLocation( anchorElem, headerHeight, parseInt(settings.offset, 10) ); // Scroll to location
+ var animationInterval; // interval timer
+ var distance = endLocation - startLocation; // distance to travel
+ var documentHeight = getDocumentHeight();
+ var timeLapsed = 0;
+ var percentage, position;
+
+ // Update URL
+ updateUrl(anchor, settings.updateURL);
+
+ /**
+ * Stop the scroll animation when it reaches its target (or the bottom/top of page)
+ * @private
+ * @param {Number} position Current position on the page
+ * @param {Number} endLocation Scroll to location
+ * @param {Number} animationInterval How much to scroll on this loop
+ */
+ var stopAnimateScroll = function (position, endLocation, animationInterval) {
+ var currentLocation = root.pageYOffset;
+ if ( position == endLocation || currentLocation == endLocation || ( (root.innerHeight + currentLocation) >= documentHeight ) ) {
+ clearInterval(animationInterval);
+ anchorElem.focus();
+ settings.callback( toggle, anchor ); // Run callbacks after animation complete
+ }
+ };
+
+ /**
+ * Loop scrolling animation
+ * @private
+ */
+ var loopAnimateScroll = function () {
+ timeLapsed += 16;
+ percentage = ( timeLapsed / parseInt(settings.speed, 10) );
+ percentage = ( percentage > 1 ) ? 1 : percentage;
+ position = startLocation + ( distance * easingPattern(settings.easing, percentage) );
+ root.scrollTo( 0, Math.floor(position) );
+ stopAnimateScroll(position, endLocation, animationInterval);
+ };
+
+ /**
+ * Set interval timer
+ * @private
+ */
+ var startAnimateScroll = function () {
+ animationInterval = setInterval(loopAnimateScroll, 16);
+ };
+
+ /**
+ * Reset position to fix weird iOS bug
+ * @link https://github.com/cferdinandi/smooth-scroll/issues/45
+ */
+ if ( root.pageYOffset === 0 ) {
+ root.scrollTo( 0, 0 );
+ }
+
+ // Start scrolling animation
+ startAnimateScroll();
+
+ };
+
+ /**
+ * If smooth scroll element clicked, animate scroll
+ * @private
+ */
+ var eventHandler = function (event) {
+ var toggle = getClosest(event.target, '[data-scroll]');
+ if ( toggle && toggle.tagName.toLowerCase() === 'a' ) {
+ event.preventDefault(); // Prevent default click event
+ smoothScroll.animateScroll( toggle, toggle.hash, settings); // Animate scroll
+ }
+ };
+
+ /**
+ * On window scroll and resize, only run events at a rate of 15fps for better performance
+ * @private
+ * @param {Function} eventTimeout Timeout function
+ * @param {Object} settings
+ */
+ var eventThrottler = function (event) {
+ if ( !eventTimeout ) {
+ eventTimeout = setTimeout(function() {
+ eventTimeout = null; // Reset timeout
+ headerHeight = getHeaderHeight( fixedHeader ); // Get the height of a fixed header if one exists
+ }, 66);
+ }
+ };
+
+ /**
+ * Destroy the current initialization.
+ * @public
+ */
+ smoothScroll.destroy = function () {
+
+ // If plugin isn't already initialized, stop
+ if ( !settings ) return;
+
+ // Remove event listeners
+ root.document.removeEventListener( 'click', eventHandler, false );
+ root.removeEventListener( 'resize', eventThrottler, false );
+
+ // Reset varaibles
+ settings = null;
+ eventTimeout = null;
+ fixedHeader = null;
+ headerHeight = null;
+ };
+
+ /**
+ * Initialize Smooth Scroll
+ * @public
+ * @param {Object} options User settings
+ */
+ smoothScroll.init = function ( options ) {
+
+ // feature test
+ if ( !supports ) return;
+
+ // Destroy any existing initializations
+ smoothScroll.destroy();
+
+ // Selectors and variables
+ settings = extend( defaults, options || {} ); // Merge user options with defaults
+ fixedHeader = root.document.querySelector('[data-scroll-header]'); // Get the fixed header
+ headerHeight = getHeaderHeight( fixedHeader );
+
+ // When a toggle is clicked, run the click handler
+ root.document.addEventListener('click', eventHandler, false );
+ if ( fixedHeader ) { root.addEventListener( 'resize', eventThrottler, false ); }
+
+ };
+
+
+ //
+ // Public APIs
+ //
+
+ return smoothScroll;
+
+});
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/smooth-scroll.min.js b/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/smooth-scroll.min.js
new file mode 100644
index 0000000..31263ee
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/dist/js/smooth-scroll.min.js
@@ -0,0 +1,2 @@
+/** smooth-scroll v7.0.0, by Chris Ferdinandi | http://github.com/cferdinandi/smooth-scroll | Licensed under MIT: http://gomakethings.com/mit/ */
+!function(e,t){"function"==typeof define&&define.amd?define(["buoy"],t(e)):"object"==typeof exports?module.exports=t(e,require("buoy")):e.smoothScroll=t(e,e.buoy)}("undefined"!=typeof global?global:this.window||this.global,function(e){"use strict";var t,n,o,r,a={},u=!!e.document.querySelector&&!!e.addEventListener,c={speed:500,easing:"easeInOutCubic",offset:0,updateURL:!0,callback:function(){}},i=function(){var e={},t=!1,n=0,o=arguments.length;"[object Boolean]"===Object.prototype.toString.call(arguments[0])&&(t=arguments[0],n++);for(var r=function(n){for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=t&&"[object Object]"===Object.prototype.toString.call(n[o])?i(!0,e[o],n[o]):n[o])};o>n;n++){var a=arguments[n];r(a)}return e},s=function(e){return Math.max(e.scrollHeight,e.offsetHeight,e.clientHeight)},l=function(e,t){var n,o,r=t.charAt(0),a="classList"in document.documentElement;for("["===r&&(t=t.substr(1,t.length-2),n=t.split("="),n.length>1&&(o=!0,n[1]=n[1].replace(/"/g,"").replace(/'/g,"")));e&&e!==document;e=e.parentNode){if("."===r)if(a){if(e.classList.contains(t.substr(1)))return e}else if(new RegExp("(^|\\s)"+t.substr(1)+"(\\s|$)").test(e.className))return e;if("#"===r&&e.id===t.substr(1))return e;if("["===r&&e.hasAttribute(n[0])){if(!o)return e;if(e.getAttribute(n[0])===n[1])return e}if(e.tagName.toLowerCase()===t)return e}return null},f=function(e){for(var t,n=String(e),o=n.length,r=-1,a="",u=n.charCodeAt(0);++r<o;){if(t=n.charCodeAt(r),0===t)throw new InvalidCharacterError("Invalid character: the input contains U+0000.");a+=t>=1&&31>=t||127==t||0===r&&t>=48&&57>=t||1===r&&t>=48&&57>=t&&45===u?"\\"+t.toString(16)+" ":t>=128||45===t||95===t||t>=48&&57>=t||t>=65&&90>=t||t>=97&&122>=t?n.charAt(r):"\\"+n.charAt(r)}return a},d=function(e,t){var n;return"easeInQuad"===e&&(n=t*t),"easeOutQuad"===e&&(n=t*(2-t)),"easeInOutQuad"===e&&(n=.5>t?2*t*t:-1+(4-2*t)*t),"easeInCubic"===e&&(n=t*t*t),"easeOutCubic"===e&&(n=--t*t*t+1),"easeInOutCubic"===e&&(n=.5>t?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1),"easeInQuart"===e&&(n=t*t*t*t),"easeOutQuart"===e&&(n=1- --t*t*t*t),"easeInOutQuart"===e&&(n=.5>t?8*t*t*t*t:1-8*--t*t*t*t),"easeInQuint"===e&&(n=t*t*t*t*t),"easeOutQuint"===e&&(n=1+--t*t*t*t*t),"easeInOutQuint"===e&&(n=.5>t?16*t*t*t*t*t:1+16*--t*t*t*t*t),n||t},h=function(e,t,n){var o=0;if(e.offsetParent)do o+=e.offsetTop,e=e.offsetParent;while(e);return o=o-t-n,o>=0?o:0},m=function(){return Math.max(e.document.body.scrollHeight,e.document.documentElement.scrollHeight,e.document.body.offsetHeight,e.document.documentElement.offsetHeight,e.document.body.clientHeight,e.document.documentElement.clientHeight)},p=function(e){return e&&"object"==typeof JSON&&"function"==typeof JSON.parse?JSON.parse(e):{}},g=function(t,n){e.history.pushState&&(n||"true"===n)&&e.history.pushState(null,null,[e.location.protocol,"//",e.location.host,e.location.pathname,e.location.search,t].join(""))},b=function(e){return null===e?0:s(e)+e.offsetTop};a.animateScroll=function(t,n,a){var u=p(t?t.getAttribute("data-options"):null),s=i(s||c,a||{},u);n="#"+f(n.substr(1));var l="#"===n?e.document.documentElement:e.document.querySelector(n),v=e.pageYOffset;o||(o=e.document.querySelector("[data-scroll-header]")),r||(r=b(o));var y,O,S,I=h(l,r,parseInt(s.offset,10)),E=I-v,L=m(),H=0;g(n,s.updateURL);var j=function(o,r,a){var u=e.pageYOffset;(o==r||u==r||e.innerHeight+u>=L)&&(clearInterval(a),l.focus(),s.callback(t,n))},w=function(){H+=16,O=H/parseInt(s.speed,10),O=O>1?1:O,S=v+E*d(s.easing,O),e.scrollTo(0,Math.floor(S)),j(S,I,y)},C=function(){y=setInterval(w,16)};0===e.pageYOffset&&e.scrollTo(0,0),C()};var v=function(e){var n=l(e.target,"[data-scroll]");n&&"a"===n.tagName.toLowerCase()&&(e.preventDefault(),a.animateScroll(n,n.hash,t))},y=function(e){n||(n=setTimeout(function(){n=null,r=b(o)},66))};return a.destroy=function(){t&&(e.document.removeEventListener("click",v,!1),e.removeEventListener("resize",y,!1),t=null,n=null,o=null,r=null)},a.init=function(n){u&&(a.destroy(),t=i(c,n||{}),o=e.document.querySelector("[data-scroll-header]"),r=b(o),e.document.addEventListener("click",v,!1),o&&e.addEventListener("resize",y,!1))},a}); \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/docs/assets/css/custom.css b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/assets/css/custom.css
new file mode 100644
index 0000000..653830a
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/assets/css/custom.css
@@ -0,0 +1,20 @@
+@-webkit-viewport { width: device-width; zoom: 1.0; }
+@-moz-viewport { width: device-width; zoom: 1.0; }
+@-ms-viewport { width: device-width; zoom: 1.0; }
+@-o-viewport { width: device-width; zoom: 1.0; }
+@viewport { width: device-width; zoom: 1.0; }
+
+html { overflow-y: auto; }
+
+img, audio, video, canvas {
+ max-width: 100%;
+ height: auto;
+}
+
+/* Sets body width */
+.container {
+ max-width: 40em;
+ width: 88%;
+ margin-left: auto;
+ margin-right: auto;
+} \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/buoy.js b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/buoy.js
new file mode 100644
index 0000000..ea39a59
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/buoy.js
@@ -0,0 +1,337 @@
+/**
+ * smooth-scroll v7.0.0
+ * Animate scrolling to anchor links, by Chris Ferdinandi.
+ * http://github.com/cferdinandi/smooth-scroll
+ *
+ * Free to use under the MIT License.
+ * http://gomakethings.com/mit/
+ */
+
+(function (root, factory) {
+ if ( typeof define === 'function' && define.amd ) {
+ define([], factory(root));
+ } else if ( typeof exports === 'object' ) {
+ module.exports = factory(root);
+ } else {
+ root.buoy = factory(root);
+ }
+})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
+
+ 'use strict';
+
+ // Object for public APIs
+ var buoy = {};
+
+
+ //
+ // Methods
+ //
+
+ /**
+ * Wait until the DOM is ready before executing code
+ * @param {Function} fn The function to execute when the DOM is ready
+ */
+ buoy.ready = function ( fn ) {
+
+ // Sanity check
+ if ( typeof fn !== 'function' ) return;
+
+ // If document is already loaded, run method
+ if ( document.readyState === 'complete' ) {
+ return fn();
+ }
+
+ // Otherwise, wait until document is loaded
+ document.addEventListener( 'DOMContentLoaded', fn, false );
+
+ };
+
+ /**
+ * A simple forEach() implementation for Arrays, Objects and NodeLists.
+ * @author Todd Motto
+ * @link https://github.com/toddmotto/foreach
+ * @param {Array|Object|NodeList} collection Collection of items to iterate
+ * @param {Function} callback Callback function for each iteration
+ * @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
+ */
+ buoy.forEach = function ( collection, callback, scope ) {
+ if ( Object.prototype.toString.call( collection ) === '[object Object]' ) {
+ for ( var prop in collection ) {
+ if ( Object.prototype.hasOwnProperty.call( collection, prop ) ) {
+ callback.call( scope, collection[prop], prop, collection );
+ }
+ }
+ } else {
+ for ( var i = 0, len = collection.length; i < len; i++ ) {
+ callback.call( scope, collection[i], i, collection );
+ }
+ }
+ };
+
+ /**
+ * Merge two or more objects. Returns a new object.
+ * @param {Boolean} deep If true, do a deep (or recursive) merge [optional]
+ * @param {Object} objects The objects to merge together
+ * @returns {Object} Merged values of defaults and options
+ */
+ buoy.extend = function () {
+
+ // Variables
+ var extended = {};
+ var deep = false;
+ var i = 0;
+ var length = arguments.length;
+
+ // Check if a deep merge
+ if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
+ deep = arguments[0];
+ i++;
+ }
+
+ // Merge the object into the extended object
+ var merge = function (obj) {
+ for ( var prop in obj ) {
+ if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
+ // If deep merge and property is an object, merge properties
+ if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
+ extended[prop] = buoy.extend( true, extended[prop], obj[prop] );
+ } else {
+ extended[prop] = obj[prop];
+ }
+ }
+ }
+ };
+
+ // Loop through each object and conduct a merge
+ for ( ; i < length; i++ ) {
+ var obj = arguments[i];
+ merge(obj);
+ }
+
+ return extended;
+
+ };
+
+ /**
+ * Get the height of an element.
+ * @param {Node} elem The element to get the height of
+ * @return {Number} The element's height in pixels
+ */
+ buoy.getHeight = function ( elem ) {
+ return Math.max( elem.scrollHeight, elem.offsetHeight, elem.clientHeight );
+ };
+
+ /**
+ * Get an element's distance from the top of the Document.
+ * @param {Node} elem The element
+ * @return {Number} Distance from the top in pixels
+ */
+ buoy.getOffsetTop = function ( elem ) {
+ var location = 0;
+ if (elem.offsetParent) {
+ do {
+ location += elem.offsetTop;
+ elem = elem.offsetParent;
+ } while (elem);
+ }
+ return location >= 0 ? location : 0;
+ };
+
+ /**
+ * Get the closest matching element up the DOM tree.
+ * @param {Element} elem Starting element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Boolean|Element} Returns null if not match found
+ */
+ buoy.getClosest = function ( elem, selector ) {
+
+ // Variables
+ var firstChar = selector.charAt(0);
+ var supports = 'classList' in document.documentElement;
+ var attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+
+ // Get closest match
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ return elem;
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ return elem;
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ return elem;
+ }
+ } else {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ return elem;
+ }
+
+ }
+
+ return null;
+
+ };
+
+ /**
+ * Get an element's parents.
+ * @param {Node} elem The element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Array} An array of matching nodes
+ */
+ buoy.getParents = function ( elem, selector ) {
+
+ // Variables
+ var parents = [];
+ var supports = 'classList' in document.documentElement;
+ var firstChar, attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( selector ) {
+ firstChar = selector.charAt(0);
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+ }
+
+ // Get matches
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+ if ( selector ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ parents.push( elem );
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ parents.push( elem );
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ parents.push( elem );
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ parents.push( elem );
+ }
+ } else {
+ parents.push( elem );
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ parents.push( elem );
+ }
+
+ } else {
+ parents.push( elem );
+ }
+
+ }
+
+ // Return parents if any exist
+ if ( parents.length === 0 ) {
+ return null;
+ } else {
+ return parents;
+ }
+
+ };
+
+ /**
+ * Get an element's siblings.
+ * @param {Node} elem The element
+ * @return {Array} An array of sibling nodes
+ */
+ buoy.getSiblings = function ( elem ) {
+
+ // Variables
+ var siblings = [];
+ var sibling = elem.parentNode.firstChild;
+
+ // Loop through all sibling nodes
+ for ( ; sibling; sibling = sibling.nextSibling ) {
+ if ( sibling.nodeType === 1 && sibling !== elem ) {
+ siblings.push( sibling );
+ }
+ }
+
+ return siblings;
+
+ };
+
+ /**
+ * Get data from a URL query string.
+ * @param {String} field The field to get from the URL
+ * @param {String} url The URL to parse
+ * @return {String} The field value
+ */
+ buoy.getQueryString = function ( field, url ) {
+ var href = url ? url : window.location.href;
+ var reg = new RegExp( '[?&]' + field + '=([^&#]*)', 'i' );
+ var string = reg.exec(href);
+ return string ? string[1] : null;
+ };
+
+
+ //
+ // Public APIs
+ //
+
+ return buoy;
+
+}); \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/buoy.min.js b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/buoy.min.js
new file mode 100644
index 0000000..fb59080
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/buoy.min.js
@@ -0,0 +1,2 @@
+/** smooth-scroll v7.0.0, by Chris Ferdinandi | http://github.com/cferdinandi/smooth-scroll | Licensed under MIT: http://gomakethings.com/mit/ */
+!function(t,e){"function"==typeof define&&define.amd?define([],e(t)):"object"==typeof exports?module.exports=e(t):t.buoy=e(t)}("undefined"!=typeof global?global:this.window||this.global,function(t){"use strict";var e={};return e.ready=function(t){return"function"==typeof t?"complete"===document.readyState?t():void document.addEventListener("DOMContentLoaded",t,!1):void 0},e.forEach=function(t,e,n){if("[object Object]"===Object.prototype.toString.call(t))for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&e.call(n,t[r],r,t);else for(var o=0,s=t.length;s>o;o++)e.call(n,t[o],o,t)},e.extend=function(){var t={},n=!1,r=0,o=arguments.length;"[object Boolean]"===Object.prototype.toString.call(arguments[0])&&(n=arguments[0],r++);for(var s=function(r){for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(t[o]=n&&"[object Object]"===Object.prototype.toString.call(r[o])?e.extend(!0,t[o],r[o]):r[o])};o>r;r++){var i=arguments[r];s(i)}return t},e.getHeight=function(t){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},e.getOffsetTop=function(t){var e=0;if(t.offsetParent)do e+=t.offsetTop,t=t.offsetParent;while(t);return e>=0?e:0},e.getClosest=function(t,e){var n,r,o=e.charAt(0),s="classList"in document.documentElement;for("["===o&&(e=e.substr(1,e.length-2),n=e.split("="),n.length>1&&(r=!0,n[1]=n[1].replace(/"/g,"").replace(/'/g,"")));t&&t!==document;t=t.parentNode){if("."===o)if(s){if(t.classList.contains(e.substr(1)))return t}else if(new RegExp("(^|\\s)"+e.substr(1)+"(\\s|$)").test(t.className))return t;if("#"===o&&t.id===e.substr(1))return t;if("["===o&&t.hasAttribute(n[0])){if(!r)return t;if(t.getAttribute(n[0])===n[1])return t}if(t.tagName.toLowerCase()===e)return t}return null},e.getParents=function(t,e){var n,r,o,s=[],i="classList"in document.documentElement;for(e&&(n=e.charAt(0),"["===n&&(e=e.substr(1,e.length-2),r=e.split("="),r.length>1&&(o=!0,r[1]=r[1].replace(/"/g,"").replace(/'/g,""))));t&&t!==document;t=t.parentNode)e?("."===n&&(i?t.classList.contains(e.substr(1))&&s.push(t):new RegExp("(^|\\s)"+e.substr(1)+"(\\s|$)").test(t.className)&&s.push(t)),"#"===n&&t.id===e.substr(1)&&s.push(t),"["===n&&t.hasAttribute(r[0])&&(o?t.getAttribute(r[0])===r[1]&&s.push(t):s.push(t)),t.tagName.toLowerCase()===e&&s.push(t)):s.push(t);return 0===s.length?null:s},e.getSiblings=function(t){for(var e=[],n=t.parentNode.firstChild;n;n=n.nextSibling)1===n.nodeType&&n!==t&&e.push(n);return e},e.getQueryString=function(t,e){var n=e?e:window.location.href,r=new RegExp("[?&]"+t+"=([^&#]*)","i"),o=r.exec(n);return o?o[1]:null},e}); \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/smooth-scroll.js b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/smooth-scroll.js
new file mode 100644
index 0000000..3edd05d
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/smooth-scroll.js
@@ -0,0 +1,484 @@
+/**
+ * smooth-scroll v7.0.0
+ * Animate scrolling to anchor links, by Chris Ferdinandi.
+ * http://github.com/cferdinandi/smooth-scroll
+ *
+ * Free to use under the MIT License.
+ * http://gomakethings.com/mit/
+ */
+
+(function (root, factory) {
+ if ( typeof define === 'function' && define.amd ) {
+ define(['buoy'], factory(root));
+ } else if ( typeof exports === 'object' ) {
+ module.exports = factory(root, require('buoy'));
+ } else {
+ root.smoothScroll = factory(root, root.buoy);
+ }
+})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
+
+ 'use strict';
+
+ //
+ // Variables
+ //
+
+ var smoothScroll = {}; // Object for public APIs
+ var supports = !!root.document.querySelector && !!root.addEventListener; // Feature test
+ var settings, eventTimeout, fixedHeader, headerHeight;
+
+ // Default settings
+ var defaults = {
+ speed: 500,
+ easing: 'easeInOutCubic',
+ offset: 0,
+ updateURL: true,
+ callback: function () {}
+ };
+
+
+ //
+ // Methods
+ //
+
+ /**
+ * Merge two or more objects. Returns a new object.
+ * @private
+ * @param {Boolean} deep If true, do a deep (or recursive) merge [optional]
+ * @param {Object} objects The objects to merge together
+ * @returns {Object} Merged values of defaults and options
+ */
+ var extend = function () {
+
+ // Variables
+ var extended = {};
+ var deep = false;
+ var i = 0;
+ var length = arguments.length;
+
+ // Check if a deep merge
+ if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
+ deep = arguments[0];
+ i++;
+ }
+
+ // Merge the object into the extended object
+ var merge = function (obj) {
+ for ( var prop in obj ) {
+ if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
+ // If deep merge and property is an object, merge properties
+ if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
+ extended[prop] = extend( true, extended[prop], obj[prop] );
+ } else {
+ extended[prop] = obj[prop];
+ }
+ }
+ }
+ };
+
+ // Loop through each object and conduct a merge
+ for ( ; i < length; i++ ) {
+ var obj = arguments[i];
+ merge(obj);
+ }
+
+ return extended;
+
+ };
+
+ /**
+ * Get the height of an element.
+ * @private
+ * @param {Node} elem The element to get the height of
+ * @return {Number} The element's height in pixels
+ */
+ var getHeight = function ( elem ) {
+ return Math.max( elem.scrollHeight, elem.offsetHeight, elem.clientHeight );
+ };
+
+ /**
+ * Get the closest matching element up the DOM tree.
+ * @private
+ * @param {Element} elem Starting element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Boolean|Element} Returns null if not match found
+ */
+ var getClosest = function ( elem, selector ) {
+
+ // Variables
+ var firstChar = selector.charAt(0);
+ var supports = 'classList' in document.documentElement;
+ var attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+
+ // Get closest match
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ return elem;
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ return elem;
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ return elem;
+ }
+ } else {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ return elem;
+ }
+
+ }
+
+ return null;
+
+ };
+
+ /**
+ * Escape special characters for use with querySelector
+ * @private
+ * @param {String} id The anchor ID to escape
+ * @author Mathias Bynens
+ * @link https://github.com/mathiasbynens/CSS.escape
+ */
+ var escapeCharacters = function ( id ) {
+ var string = String(id);
+ var length = string.length;
+ var index = -1;
+ var codeUnit;
+ var result = '';
+ var firstCodeUnit = string.charCodeAt(0);
+ while (++index < length) {
+ codeUnit = string.charCodeAt(index);
+ // Note: there’s no need to special-case astral symbols, surrogate
+ // pairs, or lone surrogates.
+
+ // If the character is NULL (U+0000), then throw an
+ // `InvalidCharacterError` exception and terminate these steps.
+ if (codeUnit === 0x0000) {
+ throw new InvalidCharacterError(
+ 'Invalid character: the input contains U+0000.'
+ );
+ }
+
+ if (
+ // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
+ // U+007F, […]
+ (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
+ // If the character is the first character and is in the range [0-9]
+ // (U+0030 to U+0039), […]
+ (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
+ // If the character is the second character and is in the range [0-9]
+ // (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
+ (
+ index === 1 &&
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
+ firstCodeUnit === 0x002D
+ )
+ ) {
+ // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
+ result += '\\' + codeUnit.toString(16) + ' ';
+ continue;
+ }
+
+ // If the character is not handled by one of the above rules and is
+ // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
+ // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
+ // U+005A), or [a-z] (U+0061 to U+007A), […]
+ if (
+ codeUnit >= 0x0080 ||
+ codeUnit === 0x002D ||
+ codeUnit === 0x005F ||
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
+ codeUnit >= 0x0041 && codeUnit <= 0x005A ||
+ codeUnit >= 0x0061 && codeUnit <= 0x007A
+ ) {
+ // the character itself
+ result += string.charAt(index);
+ continue;
+ }
+
+ // Otherwise, the escaped character.
+ // http://dev.w3.org/csswg/cssom/#escape-a-character
+ result += '\\' + string.charAt(index);
+
+ }
+ return result;
+ };
+
+ /**
+ * Calculate the easing pattern
+ * @private
+ * @link https://gist.github.com/gre/1650294
+ * @param {String} type Easing pattern
+ * @param {Number} time Time animation should take to complete
+ * @returns {Number}
+ */
+ var easingPattern = function ( type, time ) {
+ var pattern;
+ if ( type === 'easeInQuad' ) pattern = time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuad' ) pattern = time * (2 - time); // decelerating to zero velocity
+ if ( type === 'easeInOutQuad' ) pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
+ if ( type === 'easeInCubic' ) pattern = time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutCubic' ) pattern = (--time) * time * time + 1; // decelerating to zero velocity
+ if ( type === 'easeInOutCubic' ) pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
+ if ( type === 'easeInQuart' ) pattern = time * time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuart' ) pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity
+ if ( type === 'easeInOutQuart' ) pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
+ if ( type === 'easeInQuint' ) pattern = time * time * time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuint' ) pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity
+ if ( type === 'easeInOutQuint' ) pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
+ return pattern || time; // no easing, no acceleration
+ };
+
+ /**
+ * Calculate how far to scroll
+ * @private
+ * @param {Element} anchor The anchor element to scroll to
+ * @param {Number} headerHeight Height of a fixed header, if any
+ * @param {Number} offset Number of pixels by which to offset scroll
+ * @returns {Number}
+ */
+ var getEndLocation = function ( anchor, headerHeight, offset ) {
+ var location = 0;
+ if (anchor.offsetParent) {
+ do {
+ location += anchor.offsetTop;
+ anchor = anchor.offsetParent;
+ } while (anchor);
+ }
+ location = location - headerHeight - offset;
+ return location >= 0 ? location : 0;
+ };
+
+ /**
+ * Determine the document's height
+ * @private
+ * @returns {Number}
+ */
+ var getDocumentHeight = function () {
+ return Math.max(
+ root.document.body.scrollHeight, root.document.documentElement.scrollHeight,
+ root.document.body.offsetHeight, root.document.documentElement.offsetHeight,
+ root.document.body.clientHeight, root.document.documentElement.clientHeight
+ );
+ };
+
+ /**
+ * Convert data-options attribute into an object of key/value pairs
+ * @private
+ * @param {String} options Link-specific options as a data attribute string
+ * @returns {Object}
+ */
+ var getDataOptions = function ( options ) {
+ return !options || !(typeof JSON === 'object' && typeof JSON.parse === 'function') ? {} : JSON.parse( options );
+ };
+
+ /**
+ * Update the URL
+ * @private
+ * @param {Element} anchor The element to scroll to
+ * @param {Boolean} url Whether or not to update the URL history
+ */
+ var updateUrl = function ( anchor, url ) {
+ if ( root.history.pushState && (url || url === 'true') ) {
+ root.history.pushState( null, null, [root.location.protocol, '//', root.location.host, root.location.pathname, root.location.search, anchor].join('') );
+ }
+ };
+
+ var getHeaderHeight = function ( header ) {
+ return header === null ? 0 : ( getHeight( header ) + header.offsetTop );
+ };
+
+ /**
+ * Start/stop the scrolling animation
+ * @public
+ * @param {Element} toggle The element that toggled the scroll event
+ * @param {Element} anchor The element to scroll to
+ * @param {Object} options
+ */
+ smoothScroll.animateScroll = function ( toggle, anchor, options ) {
+
+ // Options and overrides
+ var overrides = getDataOptions( toggle ? toggle.getAttribute('data-options') : null );
+ var settings = extend( settings || defaults, options || {}, overrides ); // Merge user options with defaults
+ anchor = '#' + escapeCharacters(anchor.substr(1)); // Escape special characters and leading numbers
+
+ // Selectors and variables
+ var anchorElem = anchor === '#' ? root.document.documentElement : root.document.querySelector(anchor);
+ var startLocation = root.pageYOffset; // Current location on the page
+ if ( !fixedHeader ) { fixedHeader = root.document.querySelector('[data-scroll-header]'); } // Get the fixed header if not already set
+ if ( !headerHeight ) { headerHeight = getHeaderHeight( fixedHeader ); } // Get the height of a fixed header if one exists and not already set
+ var endLocation = getEndLocation( anchorElem, headerHeight, parseInt(settings.offset, 10) ); // Scroll to location
+ var animationInterval; // interval timer
+ var distance = endLocation - startLocation; // distance to travel
+ var documentHeight = getDocumentHeight();
+ var timeLapsed = 0;
+ var percentage, position;
+
+ // Update URL
+ updateUrl(anchor, settings.updateURL);
+
+ /**
+ * Stop the scroll animation when it reaches its target (or the bottom/top of page)
+ * @private
+ * @param {Number} position Current position on the page
+ * @param {Number} endLocation Scroll to location
+ * @param {Number} animationInterval How much to scroll on this loop
+ */
+ var stopAnimateScroll = function (position, endLocation, animationInterval) {
+ var currentLocation = root.pageYOffset;
+ if ( position == endLocation || currentLocation == endLocation || ( (root.innerHeight + currentLocation) >= documentHeight ) ) {
+ clearInterval(animationInterval);
+ anchorElem.focus();
+ settings.callback( toggle, anchor ); // Run callbacks after animation complete
+ }
+ };
+
+ /**
+ * Loop scrolling animation
+ * @private
+ */
+ var loopAnimateScroll = function () {
+ timeLapsed += 16;
+ percentage = ( timeLapsed / parseInt(settings.speed, 10) );
+ percentage = ( percentage > 1 ) ? 1 : percentage;
+ position = startLocation + ( distance * easingPattern(settings.easing, percentage) );
+ root.scrollTo( 0, Math.floor(position) );
+ stopAnimateScroll(position, endLocation, animationInterval);
+ };
+
+ /**
+ * Set interval timer
+ * @private
+ */
+ var startAnimateScroll = function () {
+ animationInterval = setInterval(loopAnimateScroll, 16);
+ };
+
+ /**
+ * Reset position to fix weird iOS bug
+ * @link https://github.com/cferdinandi/smooth-scroll/issues/45
+ */
+ if ( root.pageYOffset === 0 ) {
+ root.scrollTo( 0, 0 );
+ }
+
+ // Start scrolling animation
+ startAnimateScroll();
+
+ };
+
+ /**
+ * If smooth scroll element clicked, animate scroll
+ * @private
+ */
+ var eventHandler = function (event) {
+ var toggle = getClosest(event.target, '[data-scroll]');
+ if ( toggle && toggle.tagName.toLowerCase() === 'a' ) {
+ event.preventDefault(); // Prevent default click event
+ smoothScroll.animateScroll( toggle, toggle.hash, settings); // Animate scroll
+ }
+ };
+
+ /**
+ * On window scroll and resize, only run events at a rate of 15fps for better performance
+ * @private
+ * @param {Function} eventTimeout Timeout function
+ * @param {Object} settings
+ */
+ var eventThrottler = function (event) {
+ if ( !eventTimeout ) {
+ eventTimeout = setTimeout(function() {
+ eventTimeout = null; // Reset timeout
+ headerHeight = getHeaderHeight( fixedHeader ); // Get the height of a fixed header if one exists
+ }, 66);
+ }
+ };
+
+ /**
+ * Destroy the current initialization.
+ * @public
+ */
+ smoothScroll.destroy = function () {
+
+ // If plugin isn't already initialized, stop
+ if ( !settings ) return;
+
+ // Remove event listeners
+ root.document.removeEventListener( 'click', eventHandler, false );
+ root.removeEventListener( 'resize', eventThrottler, false );
+
+ // Reset varaibles
+ settings = null;
+ eventTimeout = null;
+ fixedHeader = null;
+ headerHeight = null;
+ };
+
+ /**
+ * Initialize Smooth Scroll
+ * @public
+ * @param {Object} options User settings
+ */
+ smoothScroll.init = function ( options ) {
+
+ // feature test
+ if ( !supports ) return;
+
+ // Destroy any existing initializations
+ smoothScroll.destroy();
+
+ // Selectors and variables
+ settings = extend( defaults, options || {} ); // Merge user options with defaults
+ fixedHeader = root.document.querySelector('[data-scroll-header]'); // Get the fixed header
+ headerHeight = getHeaderHeight( fixedHeader );
+
+ // When a toggle is clicked, run the click handler
+ root.document.addEventListener('click', eventHandler, false );
+ if ( fixedHeader ) { root.addEventListener( 'resize', eventThrottler, false ); }
+
+ };
+
+
+ //
+ // Public APIs
+ //
+
+ return smoothScroll;
+
+});
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/smooth-scroll.min.js b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/smooth-scroll.min.js
new file mode 100644
index 0000000..31263ee
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/dist/js/smooth-scroll.min.js
@@ -0,0 +1,2 @@
+/** smooth-scroll v7.0.0, by Chris Ferdinandi | http://github.com/cferdinandi/smooth-scroll | Licensed under MIT: http://gomakethings.com/mit/ */
+!function(e,t){"function"==typeof define&&define.amd?define(["buoy"],t(e)):"object"==typeof exports?module.exports=t(e,require("buoy")):e.smoothScroll=t(e,e.buoy)}("undefined"!=typeof global?global:this.window||this.global,function(e){"use strict";var t,n,o,r,a={},u=!!e.document.querySelector&&!!e.addEventListener,c={speed:500,easing:"easeInOutCubic",offset:0,updateURL:!0,callback:function(){}},i=function(){var e={},t=!1,n=0,o=arguments.length;"[object Boolean]"===Object.prototype.toString.call(arguments[0])&&(t=arguments[0],n++);for(var r=function(n){for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=t&&"[object Object]"===Object.prototype.toString.call(n[o])?i(!0,e[o],n[o]):n[o])};o>n;n++){var a=arguments[n];r(a)}return e},s=function(e){return Math.max(e.scrollHeight,e.offsetHeight,e.clientHeight)},l=function(e,t){var n,o,r=t.charAt(0),a="classList"in document.documentElement;for("["===r&&(t=t.substr(1,t.length-2),n=t.split("="),n.length>1&&(o=!0,n[1]=n[1].replace(/"/g,"").replace(/'/g,"")));e&&e!==document;e=e.parentNode){if("."===r)if(a){if(e.classList.contains(t.substr(1)))return e}else if(new RegExp("(^|\\s)"+t.substr(1)+"(\\s|$)").test(e.className))return e;if("#"===r&&e.id===t.substr(1))return e;if("["===r&&e.hasAttribute(n[0])){if(!o)return e;if(e.getAttribute(n[0])===n[1])return e}if(e.tagName.toLowerCase()===t)return e}return null},f=function(e){for(var t,n=String(e),o=n.length,r=-1,a="",u=n.charCodeAt(0);++r<o;){if(t=n.charCodeAt(r),0===t)throw new InvalidCharacterError("Invalid character: the input contains U+0000.");a+=t>=1&&31>=t||127==t||0===r&&t>=48&&57>=t||1===r&&t>=48&&57>=t&&45===u?"\\"+t.toString(16)+" ":t>=128||45===t||95===t||t>=48&&57>=t||t>=65&&90>=t||t>=97&&122>=t?n.charAt(r):"\\"+n.charAt(r)}return a},d=function(e,t){var n;return"easeInQuad"===e&&(n=t*t),"easeOutQuad"===e&&(n=t*(2-t)),"easeInOutQuad"===e&&(n=.5>t?2*t*t:-1+(4-2*t)*t),"easeInCubic"===e&&(n=t*t*t),"easeOutCubic"===e&&(n=--t*t*t+1),"easeInOutCubic"===e&&(n=.5>t?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1),"easeInQuart"===e&&(n=t*t*t*t),"easeOutQuart"===e&&(n=1- --t*t*t*t),"easeInOutQuart"===e&&(n=.5>t?8*t*t*t*t:1-8*--t*t*t*t),"easeInQuint"===e&&(n=t*t*t*t*t),"easeOutQuint"===e&&(n=1+--t*t*t*t*t),"easeInOutQuint"===e&&(n=.5>t?16*t*t*t*t*t:1+16*--t*t*t*t*t),n||t},h=function(e,t,n){var o=0;if(e.offsetParent)do o+=e.offsetTop,e=e.offsetParent;while(e);return o=o-t-n,o>=0?o:0},m=function(){return Math.max(e.document.body.scrollHeight,e.document.documentElement.scrollHeight,e.document.body.offsetHeight,e.document.documentElement.offsetHeight,e.document.body.clientHeight,e.document.documentElement.clientHeight)},p=function(e){return e&&"object"==typeof JSON&&"function"==typeof JSON.parse?JSON.parse(e):{}},g=function(t,n){e.history.pushState&&(n||"true"===n)&&e.history.pushState(null,null,[e.location.protocol,"//",e.location.host,e.location.pathname,e.location.search,t].join(""))},b=function(e){return null===e?0:s(e)+e.offsetTop};a.animateScroll=function(t,n,a){var u=p(t?t.getAttribute("data-options"):null),s=i(s||c,a||{},u);n="#"+f(n.substr(1));var l="#"===n?e.document.documentElement:e.document.querySelector(n),v=e.pageYOffset;o||(o=e.document.querySelector("[data-scroll-header]")),r||(r=b(o));var y,O,S,I=h(l,r,parseInt(s.offset,10)),E=I-v,L=m(),H=0;g(n,s.updateURL);var j=function(o,r,a){var u=e.pageYOffset;(o==r||u==r||e.innerHeight+u>=L)&&(clearInterval(a),l.focus(),s.callback(t,n))},w=function(){H+=16,O=H/parseInt(s.speed,10),O=O>1?1:O,S=v+E*d(s.easing,O),e.scrollTo(0,Math.floor(S)),j(S,I,y)},C=function(){y=setInterval(w,16)};0===e.pageYOffset&&e.scrollTo(0,0),C()};var v=function(e){var n=l(e.target,"[data-scroll]");n&&"a"===n.tagName.toLowerCase()&&(e.preventDefault(),a.animateScroll(n,n.hash,t))},y=function(e){n||(n=setTimeout(function(){n=null,r=b(o)},66))};return a.destroy=function(){t&&(e.document.removeEventListener("click",v,!1),e.removeEventListener("resize",y,!1),t=null,n=null,o=null,r=null)},a.init=function(n){u&&(a.destroy(),t=i(c,n||{}),o=e.document.querySelector("[data-scroll-header]"),r=b(o),e.document.addEventListener("click",v,!1),o&&e.addEventListener("resize",y,!1))},a}); \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/docs/index.html b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/index.html
new file mode 100644
index 0000000..ab6d52c
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/docs/index.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <title>Smooth Scroll</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <!-- stylesheets -->
+ <link rel="stylesheet" href="assets/css/custom.css" type="text/css">
+ </head>
+
+ <body>
+
+ <main class="container" id="top">
+
+ <nav>
+ <h1>Smooth Scroll</h1>
+ <p><a href="https://github.com/cferdinandi/smooth-scroll">GitHub</a></p>
+ <hr>
+ </nav>
+
+ <section>
+ <p>
+ <strong>Linear</strong><br>
+ <a data-scroll data-options='{ "easing": "linear" }' href="#bazinga">Linear (no other options)</a><br>
+ </p>
+
+ <p>
+ <strong>Ease-In</strong><br>
+ <a data-scroll data-options='{ "easing": "easeInQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeInCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeInQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeInQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ <strong>Ease-In-Out</strong><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ <strong>Ease-Out</strong><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
+ </p>
+
+ <p id="bazinga"><a data-scroll href="#1@#%^-bottom">Bazinga!</a></p>
+
+ <p>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
+ </p>
+
+ <p id="1@#%^-bottom"><a data-scroll data-options='{ "easing": "easeOutCubic" }' href="#">Back to the top</a></p>
+ </section>
+ </main>
+
+ <!-- Javascript -->
+ <script src='dist/js/buoy.js'></script>
+ <script src='dist/js/smooth-scroll.js'></script>
+ <script>
+ smoothScroll.init({
+ speed: 1000,
+ easing: 'easeInOutCubic',
+ offset: 0,
+ updateURL: true,
+ callback: function ( toggle, anchor ) {}
+ });
+ </script>
+
+
+ </body>
+</html> \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/gulpfile.js b/static/website/bootstrap-css/bower_components/smooth-scroll/gulpfile.js
new file mode 100644
index 0000000..77e3ff6
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/gulpfile.js
@@ -0,0 +1,297 @@
+/**
+ * Gulp Packages
+ */
+
+// General
+var gulp = require('gulp');
+var fs = require('fs');
+var del = require('del');
+var lazypipe = require('lazypipe');
+var plumber = require('gulp-plumber');
+var flatten = require('gulp-flatten');
+var tap = require('gulp-tap');
+var rename = require('gulp-rename');
+var header = require('gulp-header');
+var footer = require('gulp-footer');
+var watch = require('gulp-watch');
+var livereload = require('gulp-livereload');
+var package = require('./package.json');
+
+// Scripts and tests
+var jshint = require('gulp-jshint');
+var stylish = require('jshint-stylish');
+var concat = require('gulp-concat');
+var uglify = require('gulp-uglify');
+var karma = require('gulp-karma');
+
+// Styles
+var sass = require('gulp-sass');
+var prefix = require('gulp-autoprefixer');
+var minify = require('gulp-minify-css');
+
+// SVGs
+var svgmin = require('gulp-svgmin');
+var svgstore = require('gulp-svgstore');
+
+// Docs
+var markdown = require('gulp-markdown');
+var fileinclude = require('gulp-file-include');
+
+
+/**
+ * Paths to project folders
+ */
+
+var paths = {
+ input: 'src/**/*',
+ output: 'dist/',
+ scripts: {
+ input: 'src/js/*',
+ output: 'dist/js/'
+ },
+ styles: {
+ input: 'src/sass/**/*.{scss,sass}',
+ output: 'dist/css/'
+ },
+ svgs: {
+ input: 'src/svg/*',
+ output: 'dist/svg/'
+ },
+ static: 'src/static/**',
+ test: {
+ input: 'src/js/**/*.js',
+ karma: 'test/karma.conf.js',
+ spec: 'test/spec/**/*.js',
+ coverage: 'test/coverage/',
+ results: 'test/results/'
+ },
+ docs: {
+ input: 'src/docs/*.{html,md,markdown}',
+ output: 'docs/',
+ templates: 'src/docs/_templates/',
+ assets: 'src/docs/assets/**'
+ }
+};
+
+
+/**
+ * Template for banner to add to file headers
+ */
+
+var banner = {
+ full :
+ '/**\n' +
+ ' * <%= package.name %> v<%= package.version %>\n' +
+ ' * <%= package.description %>, by <%= package.author.name %>.\n' +
+ ' * <%= package.repository.url %>\n' +
+ ' * \n' +
+ ' * Free to use under the MIT License.\n' +
+ ' * http://gomakethings.com/mit/\n' +
+ ' */\n\n',
+ min :
+ '/**' +
+ ' <%= package.name %> v<%= package.version %>, by Chris Ferdinandi' +
+ ' | <%= package.repository.url %>' +
+ ' | Licensed under MIT: http://gomakethings.com/mit/' +
+ ' */\n'
+};
+
+
+/**
+ * Gulp Taks
+ */
+
+// Lint, minify, and concatenate scripts
+gulp.task('build:scripts', ['clean:dist'], function() {
+ var jsTasks = lazypipe()
+ .pipe(header, banner.full, { package : package })
+ .pipe(gulp.dest, paths.scripts.output)
+ .pipe(rename, { suffix: '.min' })
+ .pipe(uglify)
+ .pipe(header, banner.min, { package : package })
+ .pipe(gulp.dest, paths.scripts.output);
+
+ return gulp.src(paths.scripts.input)
+ .pipe(plumber())
+ .pipe(tap(function (file, t) {
+ if ( file.isDirectory() ) {
+ var name = file.relative + '.js';
+ return gulp.src(file.path + '/*.js')
+ .pipe(concat(name))
+ .pipe(jsTasks());
+ }
+ }))
+ .pipe(jsTasks());
+});
+
+// Process, lint, and minify Sass files
+gulp.task('build:styles', ['clean:dist'], function() {
+ return gulp.src(paths.styles.input)
+ .pipe(plumber())
+ .pipe(sass({
+ outputStyle: 'expanded',
+ sourceComments: true
+ }))
+ .pipe(flatten())
+ .pipe(prefix({
+ browsers: ['last 2 version', '> 1%'],
+ cascade: true,
+ remove: true
+ }))
+ .pipe(header(banner.full, { package : package }))
+ .pipe(gulp.dest(paths.styles.output))
+ .pipe(rename({ suffix: '.min' }))
+ .pipe(minify())
+ .pipe(header(banner.min, { package : package }))
+ .pipe(gulp.dest(paths.styles.output));
+});
+
+// Generate SVG sprites
+gulp.task('build:svgs', ['clean:dist'], function () {
+ return gulp.src(paths.svgs.input)
+ .pipe(plumber())
+ .pipe(tap(function (file, t) {
+ if ( file.isDirectory() ) {
+ var name = file.relative + '.svg';
+ return gulp.src(file.path + '/*.svg')
+ .pipe(svgmin())
+ .pipe(svgstore({
+ fileName: name,
+ prefix: 'icon-',
+ inlineSvg: true
+ }))
+ .pipe(gulp.dest(paths.svgs.output));
+ }
+ }))
+ .pipe(svgmin())
+ .pipe(svgstore({
+ fileName: 'icons.svg',
+ prefix: 'icon-',
+ inlineSvg: true
+ }))
+ .pipe(gulp.dest(paths.svgs.output));
+});
+
+// Copy static files into output folder
+gulp.task('copy:static', ['clean:dist'], function() {
+ return gulp.src(paths.static)
+ .pipe(plumber())
+ .pipe(gulp.dest(paths.output));
+});
+
+// Lint scripts
+gulp.task('lint:scripts', function () {
+ return gulp.src(paths.scripts.input)
+ .pipe(plumber())
+ .pipe(jshint())
+ .pipe(jshint.reporter('jshint-stylish'));
+});
+
+// Remove prexisting content from output and test folders
+gulp.task('clean:dist', function () {
+ del.sync([
+ paths.output,
+ paths.test.coverage,
+ paths.test.results
+ ]);
+});
+
+// Run unit tests
+gulp.task('test:scripts', function() {
+ return gulp.src([paths.test.input].concat([paths.test.spec]))
+ .pipe(plumber())
+ .pipe(karma({ configFile: paths.test.karma }))
+ .on('error', function(err) { throw err; });
+});
+
+// Generate documentation
+gulp.task('build:docs', ['compile', 'clean:docs'], function() {
+ return gulp.src(paths.docs.input)
+ .pipe(plumber())
+ .pipe(fileinclude({
+ prefix: '@@',
+ basepath: '@file'
+ }))
+ .pipe(tap(function (file, t) {
+ if ( /\.md|\.markdown/.test(file.path) ) {
+ return t.through(markdown);
+ }
+ }))
+ .pipe(header(fs.readFileSync(paths.docs.templates + '/_header.html', 'utf8')))
+ .pipe(footer(fs.readFileSync(paths.docs.templates + '/_footer.html', 'utf8')))
+ .pipe(gulp.dest(paths.docs.output));
+});
+
+// Copy distribution files to docs
+gulp.task('copy:dist', ['compile', 'clean:docs'], function() {
+ return gulp.src(paths.output + '/**')
+ .pipe(plumber())
+ .pipe(gulp.dest(paths.docs.output + '/dist'));
+});
+
+// Copy documentation assets to docs
+gulp.task('copy:assets', ['clean:docs'], function() {
+ return gulp.src(paths.docs.assets)
+ .pipe(plumber())
+ .pipe(gulp.dest(paths.docs.output + '/assets'));
+});
+
+// Remove prexisting content from docs folder
+gulp.task('clean:docs', function () {
+ return del.sync(paths.docs.output);
+});
+
+// Spin up livereload server and listen for file changes
+gulp.task('listen', function () {
+ livereload.listen();
+ gulp.watch(paths.input).on('change', function(file) {
+ gulp.start('default');
+ gulp.start('refresh');
+ });
+});
+
+// Run livereload after file change
+gulp.task('refresh', ['compile', 'docs'], function () {
+ livereload.changed();
+});
+
+
+/**
+ * Task Runners
+ */
+
+// Compile files
+gulp.task('compile', [
+ 'lint:scripts',
+ 'clean:dist',
+ 'copy:static',
+ 'build:scripts',
+ 'build:svgs',
+ 'build:styles'
+]);
+
+// Generate documentation
+gulp.task('docs', [
+ 'clean:docs',
+ 'build:docs',
+ 'copy:dist',
+ 'copy:assets'
+]);
+
+// Generate documentation
+gulp.task('tests', [
+ 'test:scripts'
+]);
+
+// Compile files, generate docs, and run unit tests (default)
+gulp.task('default', [
+ 'compile',
+ 'docs',
+ 'tests'
+]);
+
+// Compile files, generate docs, and run unit tests when something changes
+gulp.task('watch', [
+ 'listen',
+ 'default'
+]); \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/index.html b/static/website/bootstrap-css/bower_components/smooth-scroll/index.html
new file mode 100644
index 0000000..459ca3e
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/index.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Smooth Scroll</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <!-- HTML5 Shim for IE -->
+ <!--[if IE]>
+ <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+</head>
+
+<body id="top">
+ <section style="width: 88%; max-width: 40em; margin-left: auto; margin-right: auto;">
+
+ <h1 style="text-align: center; font-size: 3em; margin-bottom: 0;">Smooth Scroll</h1>
+ <p style="text-align: center; font-size: 1.5em; margin: 0;">A lightweight script to animate scrolling to anchor links.</p>
+ <p style="text-align: center;"><a href="https://github.com/cferdinandi/smooth-scroll#readme">Smooth Scroll on GitHub</a></p>
+
+ <br><br>
+
+ <p>
+ <strong>Linear</strong><br>
+ <a data-scroll data-options='{ "easing": "linear" }' href="#bazinga">Linear (no other options)</a><br>
+ </p>
+
+ <p>
+ <strong>Ease-In</strong><br>
+ <a data-scroll data-options='{ "easing": "easeInQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeInCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeInQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeInQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ <strong>Ease-In-Out</strong><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ <strong>Ease-Out</strong><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
+ </p>
+
+ <p id="bazinga"><a data-scroll href="#1@#%^-bottom">Bazinga!</a></p>
+
+ <p>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
+ </p>
+
+ <p id="1@#%^-bottom"><a data-scroll data-options='{ "easing": "easeOutCubic" }' href="#top">Back to the top</a></p>
+
+ </section>
+
+
+ <!-- Javascript -->
+ <script src='dist/js/bind-polyfill.js'></script>
+ <script src='dist/js/smooth-scroll.js'></script>
+ <script>
+ smoothScroll.init({
+ speed: 1000,
+ easing: 'easeInOutCubic',
+ offset: 0,
+ updateURL: true,
+ callbackBefore: function ( toggle, anchor ) {},
+ callbackAfter: function ( toggle, anchor ) {}
+ });
+ </script>
+
+</body>
+</html>
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/package.json b/static/website/bootstrap-css/bower_components/smooth-scroll/package.json
new file mode 100644
index 0000000..ffc1677
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "smooth-scroll",
+ "version": "7.0.0",
+ "description": "Animate scrolling to anchor links",
+ "main": "./dist/js/smooth-scroll.js",
+ "author": {
+ "name": "Chris Ferdinandi",
+ "url": "http://gomakethings.com"
+ },
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/cferdinandi/smooth-scroll"
+ },
+ "devDependencies": {
+ "gulp": "^3.9.0",
+ "node-fs": "^0.1.7",
+ "del": "^1.2.0",
+ "lazypipe": "^0.2.4",
+ "gulp-plumber": "^1.0.1",
+ "gulp-flatten": "^0.0.4",
+ "gulp-tap": "^0.1.3",
+ "gulp-rename": "^1.2.2",
+ "gulp-header": "^1.2.2",
+ "gulp-footer": "^1.0.5",
+ "gulp-watch": "^4.2.4",
+ "gulp-livereload": "^3.8.0",
+ "gulp-jshint": "^1.11.1",
+ "jshint-stylish": "^2.0.1",
+ "gulp-concat": "^2.6.0",
+ "gulp-uglify": "^1.2.0",
+ "karma": "^0.12.37",
+ "gulp-karma": "^0.0.4",
+ "karma-coverage": "^0.4.2",
+ "jasmine": "^2.3.1",
+ "karma-jasmine": "^0.3.6",
+ "karma-phantomjs-launcher": "^0.2.0",
+ "karma-spec-reporter": "^0.0.19",
+ "karma-htmlfile-reporter": "^0.2.1",
+ "gulp-sass": "^2.0.3",
+ "gulp-minify-css": "^1.2.0",
+ "gulp-autoprefixer": "^2.3.1",
+ "gulp-svgmin": "^1.1.2",
+ "gulp-svgstore": "^5.0.2",
+ "gulp-markdown": "^1.0.0",
+ "gulp-file-include": "^0.11.1"
+ }
+}
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/_templates/_footer.html b/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/_templates/_footer.html
new file mode 100644
index 0000000..d8d3a12
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/_templates/_footer.html
@@ -0,0 +1,20 @@
+
+ </section>
+ </main>
+
+ <!-- Javascript -->
+ <script src='dist/js/buoy.js'></script>
+ <script src='dist/js/smooth-scroll.js'></script>
+ <script>
+ smoothScroll.init({
+ speed: 1000,
+ easing: 'easeInOutCubic',
+ offset: 0,
+ updateURL: true,
+ callback: function ( toggle, anchor ) {}
+ });
+ </script>
+
+
+ </body>
+</html> \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/_templates/_header.html b/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/_templates/_header.html
new file mode 100644
index 0000000..217d982
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/_templates/_header.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <title>Smooth Scroll</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+ <!-- stylesheets -->
+ <link rel="stylesheet" href="assets/css/custom.css" type="text/css">
+ </head>
+
+ <body>
+
+ <main class="container" id="top">
+
+ <nav>
+ <h1>Smooth Scroll</h1>
+ <p><a href="https://github.com/cferdinandi/smooth-scroll">GitHub</a></p>
+ <hr>
+ </nav>
+
+ <section>
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/assets/css/custom.css b/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/assets/css/custom.css
new file mode 100644
index 0000000..653830a
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/assets/css/custom.css
@@ -0,0 +1,20 @@
+@-webkit-viewport { width: device-width; zoom: 1.0; }
+@-moz-viewport { width: device-width; zoom: 1.0; }
+@-ms-viewport { width: device-width; zoom: 1.0; }
+@-o-viewport { width: device-width; zoom: 1.0; }
+@viewport { width: device-width; zoom: 1.0; }
+
+html { overflow-y: auto; }
+
+img, audio, video, canvas {
+ max-width: 100%;
+ height: auto;
+}
+
+/* Sets body width */
+.container {
+ max-width: 40em;
+ width: 88%;
+ margin-left: auto;
+ margin-right: auto;
+} \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/index.html b/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/index.html
new file mode 100644
index 0000000..1dd9971
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/src/docs/index.html
@@ -0,0 +1,44 @@
+ <p>
+ <strong>Linear</strong><br>
+ <a data-scroll data-options='{ "easing": "linear" }' href="#bazinga">Linear (no other options)</a><br>
+ </p>
+
+ <p>
+ <strong>Ease-In</strong><br>
+ <a data-scroll data-options='{ "easing": "easeInQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeInCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeInQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeInQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ <strong>Ease-In-Out</strong><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeInOutQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ <strong>Ease-Out</strong><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuad" }' href="#bazinga">Quad</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutCubic" }' href="#bazinga">Cubic</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuart" }' href="#bazinga">Quart</a><br>
+ <a data-scroll data-options='{ "easing": "easeOutQuint" }' href="#bazinga">Quint</a>
+ </p>
+
+ <p>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
+ </p>
+
+ <p id="bazinga"><a data-scroll href="#1@#%^-bottom">Bazinga!</a></p>
+
+ <p>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
+ .<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
+ </p>
+
+ <p id="1@#%^-bottom"><a data-scroll data-options='{ "easing": "easeOutCubic" }' href="#">Back to the top</a></p> \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/src/js/buoy.js b/static/website/bootstrap-css/bower_components/smooth-scroll/src/js/buoy.js
new file mode 100644
index 0000000..b9e4be7
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/src/js/buoy.js
@@ -0,0 +1,328 @@
+(function (root, factory) {
+ if ( typeof define === 'function' && define.amd ) {
+ define([], factory(root));
+ } else if ( typeof exports === 'object' ) {
+ module.exports = factory(root);
+ } else {
+ root.buoy = factory(root);
+ }
+})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
+
+ 'use strict';
+
+ // Object for public APIs
+ var buoy = {};
+
+
+ //
+ // Methods
+ //
+
+ /**
+ * Wait until the DOM is ready before executing code
+ * @param {Function} fn The function to execute when the DOM is ready
+ */
+ buoy.ready = function ( fn ) {
+
+ // Sanity check
+ if ( typeof fn !== 'function' ) return;
+
+ // If document is already loaded, run method
+ if ( document.readyState === 'complete' ) {
+ return fn();
+ }
+
+ // Otherwise, wait until document is loaded
+ document.addEventListener( 'DOMContentLoaded', fn, false );
+
+ };
+
+ /**
+ * A simple forEach() implementation for Arrays, Objects and NodeLists.
+ * @author Todd Motto
+ * @link https://github.com/toddmotto/foreach
+ * @param {Array|Object|NodeList} collection Collection of items to iterate
+ * @param {Function} callback Callback function for each iteration
+ * @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
+ */
+ buoy.forEach = function ( collection, callback, scope ) {
+ if ( Object.prototype.toString.call( collection ) === '[object Object]' ) {
+ for ( var prop in collection ) {
+ if ( Object.prototype.hasOwnProperty.call( collection, prop ) ) {
+ callback.call( scope, collection[prop], prop, collection );
+ }
+ }
+ } else {
+ for ( var i = 0, len = collection.length; i < len; i++ ) {
+ callback.call( scope, collection[i], i, collection );
+ }
+ }
+ };
+
+ /**
+ * Merge two or more objects. Returns a new object.
+ * @param {Boolean} deep If true, do a deep (or recursive) merge [optional]
+ * @param {Object} objects The objects to merge together
+ * @returns {Object} Merged values of defaults and options
+ */
+ buoy.extend = function () {
+
+ // Variables
+ var extended = {};
+ var deep = false;
+ var i = 0;
+ var length = arguments.length;
+
+ // Check if a deep merge
+ if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
+ deep = arguments[0];
+ i++;
+ }
+
+ // Merge the object into the extended object
+ var merge = function (obj) {
+ for ( var prop in obj ) {
+ if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
+ // If deep merge and property is an object, merge properties
+ if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
+ extended[prop] = buoy.extend( true, extended[prop], obj[prop] );
+ } else {
+ extended[prop] = obj[prop];
+ }
+ }
+ }
+ };
+
+ // Loop through each object and conduct a merge
+ for ( ; i < length; i++ ) {
+ var obj = arguments[i];
+ merge(obj);
+ }
+
+ return extended;
+
+ };
+
+ /**
+ * Get the height of an element.
+ * @param {Node} elem The element to get the height of
+ * @return {Number} The element's height in pixels
+ */
+ buoy.getHeight = function ( elem ) {
+ return Math.max( elem.scrollHeight, elem.offsetHeight, elem.clientHeight );
+ };
+
+ /**
+ * Get an element's distance from the top of the Document.
+ * @param {Node} elem The element
+ * @return {Number} Distance from the top in pixels
+ */
+ buoy.getOffsetTop = function ( elem ) {
+ var location = 0;
+ if (elem.offsetParent) {
+ do {
+ location += elem.offsetTop;
+ elem = elem.offsetParent;
+ } while (elem);
+ }
+ return location >= 0 ? location : 0;
+ };
+
+ /**
+ * Get the closest matching element up the DOM tree.
+ * @param {Element} elem Starting element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Boolean|Element} Returns null if not match found
+ */
+ buoy.getClosest = function ( elem, selector ) {
+
+ // Variables
+ var firstChar = selector.charAt(0);
+ var supports = 'classList' in document.documentElement;
+ var attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+
+ // Get closest match
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ return elem;
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ return elem;
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ return elem;
+ }
+ } else {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ return elem;
+ }
+
+ }
+
+ return null;
+
+ };
+
+ /**
+ * Get an element's parents.
+ * @param {Node} elem The element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Array} An array of matching nodes
+ */
+ buoy.getParents = function ( elem, selector ) {
+
+ // Variables
+ var parents = [];
+ var supports = 'classList' in document.documentElement;
+ var firstChar, attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( selector ) {
+ firstChar = selector.charAt(0);
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+ }
+
+ // Get matches
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+ if ( selector ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ parents.push( elem );
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ parents.push( elem );
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ parents.push( elem );
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ parents.push( elem );
+ }
+ } else {
+ parents.push( elem );
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ parents.push( elem );
+ }
+
+ } else {
+ parents.push( elem );
+ }
+
+ }
+
+ // Return parents if any exist
+ if ( parents.length === 0 ) {
+ return null;
+ } else {
+ return parents;
+ }
+
+ };
+
+ /**
+ * Get an element's siblings.
+ * @param {Node} elem The element
+ * @return {Array} An array of sibling nodes
+ */
+ buoy.getSiblings = function ( elem ) {
+
+ // Variables
+ var siblings = [];
+ var sibling = elem.parentNode.firstChild;
+
+ // Loop through all sibling nodes
+ for ( ; sibling; sibling = sibling.nextSibling ) {
+ if ( sibling.nodeType === 1 && sibling !== elem ) {
+ siblings.push( sibling );
+ }
+ }
+
+ return siblings;
+
+ };
+
+ /**
+ * Get data from a URL query string.
+ * @param {String} field The field to get from the URL
+ * @param {String} url The URL to parse
+ * @return {String} The field value
+ */
+ buoy.getQueryString = function ( field, url ) {
+ var href = url ? url : window.location.href;
+ var reg = new RegExp( '[?&]' + field + '=([^&#]*)', 'i' );
+ var string = reg.exec(href);
+ return string ? string[1] : null;
+ };
+
+
+ //
+ // Public APIs
+ //
+
+ return buoy;
+
+}); \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/src/js/smooth-scroll.js b/static/website/bootstrap-css/bower_components/smooth-scroll/src/js/smooth-scroll.js
new file mode 100644
index 0000000..336c715
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/src/js/smooth-scroll.js
@@ -0,0 +1,475 @@
+(function (root, factory) {
+ if ( typeof define === 'function' && define.amd ) {
+ define(['buoy'], factory(root));
+ } else if ( typeof exports === 'object' ) {
+ module.exports = factory(root, require('buoy'));
+ } else {
+ root.smoothScroll = factory(root, root.buoy);
+ }
+})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
+
+ 'use strict';
+
+ //
+ // Variables
+ //
+
+ var smoothScroll = {}; // Object for public APIs
+ var supports = !!root.document.querySelector && !!root.addEventListener; // Feature test
+ var settings, eventTimeout, fixedHeader, headerHeight;
+
+ // Default settings
+ var defaults = {
+ speed: 500,
+ easing: 'easeInOutCubic',
+ offset: 0,
+ updateURL: true,
+ callback: function () {}
+ };
+
+
+ //
+ // Methods
+ //
+
+ /**
+ * Merge two or more objects. Returns a new object.
+ * @private
+ * @param {Boolean} deep If true, do a deep (or recursive) merge [optional]
+ * @param {Object} objects The objects to merge together
+ * @returns {Object} Merged values of defaults and options
+ */
+ var extend = function () {
+
+ // Variables
+ var extended = {};
+ var deep = false;
+ var i = 0;
+ var length = arguments.length;
+
+ // Check if a deep merge
+ if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
+ deep = arguments[0];
+ i++;
+ }
+
+ // Merge the object into the extended object
+ var merge = function (obj) {
+ for ( var prop in obj ) {
+ if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
+ // If deep merge and property is an object, merge properties
+ if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
+ extended[prop] = extend( true, extended[prop], obj[prop] );
+ } else {
+ extended[prop] = obj[prop];
+ }
+ }
+ }
+ };
+
+ // Loop through each object and conduct a merge
+ for ( ; i < length; i++ ) {
+ var obj = arguments[i];
+ merge(obj);
+ }
+
+ return extended;
+
+ };
+
+ /**
+ * Get the height of an element.
+ * @private
+ * @param {Node} elem The element to get the height of
+ * @return {Number} The element's height in pixels
+ */
+ var getHeight = function ( elem ) {
+ return Math.max( elem.scrollHeight, elem.offsetHeight, elem.clientHeight );
+ };
+
+ /**
+ * Get the closest matching element up the DOM tree.
+ * @private
+ * @param {Element} elem Starting element
+ * @param {String} selector Selector to match against (class, ID, data attribute, or tag)
+ * @return {Boolean|Element} Returns null if not match found
+ */
+ var getClosest = function ( elem, selector ) {
+
+ // Variables
+ var firstChar = selector.charAt(0);
+ var supports = 'classList' in document.documentElement;
+ var attribute, value;
+
+ // If selector is a data attribute, split attribute from value
+ if ( firstChar === '[' ) {
+ selector = selector.substr(1, selector.length - 2);
+ attribute = selector.split( '=' );
+
+ if ( attribute.length > 1 ) {
+ value = true;
+ attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
+ }
+ }
+
+ // Get closest match
+ for ( ; elem && elem !== document; elem = elem.parentNode ) {
+
+ // If selector is a class
+ if ( firstChar === '.' ) {
+ if ( supports ) {
+ if ( elem.classList.contains( selector.substr(1) ) ) {
+ return elem;
+ }
+ } else {
+ if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is an ID
+ if ( firstChar === '#' ) {
+ if ( elem.id === selector.substr(1) ) {
+ return elem;
+ }
+ }
+
+ // If selector is a data attribute
+ if ( firstChar === '[' ) {
+ if ( elem.hasAttribute( attribute[0] ) ) {
+ if ( value ) {
+ if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
+ return elem;
+ }
+ } else {
+ return elem;
+ }
+ }
+ }
+
+ // If selector is a tag
+ if ( elem.tagName.toLowerCase() === selector ) {
+ return elem;
+ }
+
+ }
+
+ return null;
+
+ };
+
+ /**
+ * Escape special characters for use with querySelector
+ * @private
+ * @param {String} id The anchor ID to escape
+ * @author Mathias Bynens
+ * @link https://github.com/mathiasbynens/CSS.escape
+ */
+ var escapeCharacters = function ( id ) {
+ var string = String(id);
+ var length = string.length;
+ var index = -1;
+ var codeUnit;
+ var result = '';
+ var firstCodeUnit = string.charCodeAt(0);
+ while (++index < length) {
+ codeUnit = string.charCodeAt(index);
+ // Note: there’s no need to special-case astral symbols, surrogate
+ // pairs, or lone surrogates.
+
+ // If the character is NULL (U+0000), then throw an
+ // `InvalidCharacterError` exception and terminate these steps.
+ if (codeUnit === 0x0000) {
+ throw new InvalidCharacterError(
+ 'Invalid character: the input contains U+0000.'
+ );
+ }
+
+ if (
+ // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
+ // U+007F, […]
+ (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
+ // If the character is the first character and is in the range [0-9]
+ // (U+0030 to U+0039), […]
+ (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
+ // If the character is the second character and is in the range [0-9]
+ // (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
+ (
+ index === 1 &&
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
+ firstCodeUnit === 0x002D
+ )
+ ) {
+ // http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
+ result += '\\' + codeUnit.toString(16) + ' ';
+ continue;
+ }
+
+ // If the character is not handled by one of the above rules and is
+ // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
+ // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
+ // U+005A), or [a-z] (U+0061 to U+007A), […]
+ if (
+ codeUnit >= 0x0080 ||
+ codeUnit === 0x002D ||
+ codeUnit === 0x005F ||
+ codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
+ codeUnit >= 0x0041 && codeUnit <= 0x005A ||
+ codeUnit >= 0x0061 && codeUnit <= 0x007A
+ ) {
+ // the character itself
+ result += string.charAt(index);
+ continue;
+ }
+
+ // Otherwise, the escaped character.
+ // http://dev.w3.org/csswg/cssom/#escape-a-character
+ result += '\\' + string.charAt(index);
+
+ }
+ return result;
+ };
+
+ /**
+ * Calculate the easing pattern
+ * @private
+ * @link https://gist.github.com/gre/1650294
+ * @param {String} type Easing pattern
+ * @param {Number} time Time animation should take to complete
+ * @returns {Number}
+ */
+ var easingPattern = function ( type, time ) {
+ var pattern;
+ if ( type === 'easeInQuad' ) pattern = time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuad' ) pattern = time * (2 - time); // decelerating to zero velocity
+ if ( type === 'easeInOutQuad' ) pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
+ if ( type === 'easeInCubic' ) pattern = time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutCubic' ) pattern = (--time) * time * time + 1; // decelerating to zero velocity
+ if ( type === 'easeInOutCubic' ) pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
+ if ( type === 'easeInQuart' ) pattern = time * time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuart' ) pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity
+ if ( type === 'easeInOutQuart' ) pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
+ if ( type === 'easeInQuint' ) pattern = time * time * time * time * time; // accelerating from zero velocity
+ if ( type === 'easeOutQuint' ) pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity
+ if ( type === 'easeInOutQuint' ) pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
+ return pattern || time; // no easing, no acceleration
+ };
+
+ /**
+ * Calculate how far to scroll
+ * @private
+ * @param {Element} anchor The anchor element to scroll to
+ * @param {Number} headerHeight Height of a fixed header, if any
+ * @param {Number} offset Number of pixels by which to offset scroll
+ * @returns {Number}
+ */
+ var getEndLocation = function ( anchor, headerHeight, offset ) {
+ var location = 0;
+ if (anchor.offsetParent) {
+ do {
+ location += anchor.offsetTop;
+ anchor = anchor.offsetParent;
+ } while (anchor);
+ }
+ location = location - headerHeight - offset;
+ return location >= 0 ? location : 0;
+ };
+
+ /**
+ * Determine the document's height
+ * @private
+ * @returns {Number}
+ */
+ var getDocumentHeight = function () {
+ return Math.max(
+ root.document.body.scrollHeight, root.document.documentElement.scrollHeight,
+ root.document.body.offsetHeight, root.document.documentElement.offsetHeight,
+ root.document.body.clientHeight, root.document.documentElement.clientHeight
+ );
+ };
+
+ /**
+ * Convert data-options attribute into an object of key/value pairs
+ * @private
+ * @param {String} options Link-specific options as a data attribute string
+ * @returns {Object}
+ */
+ var getDataOptions = function ( options ) {
+ return !options || !(typeof JSON === 'object' && typeof JSON.parse === 'function') ? {} : JSON.parse( options );
+ };
+
+ /**
+ * Update the URL
+ * @private
+ * @param {Element} anchor The element to scroll to
+ * @param {Boolean} url Whether or not to update the URL history
+ */
+ var updateUrl = function ( anchor, url ) {
+ if ( root.history.pushState && (url || url === 'true') ) {
+ root.history.pushState( null, null, [root.location.protocol, '//', root.location.host, root.location.pathname, root.location.search, anchor].join('') );
+ }
+ };
+
+ var getHeaderHeight = function ( header ) {
+ return header === null ? 0 : ( getHeight( header ) + header.offsetTop );
+ };
+
+ /**
+ * Start/stop the scrolling animation
+ * @public
+ * @param {Element} toggle The element that toggled the scroll event
+ * @param {Element} anchor The element to scroll to
+ * @param {Object} options
+ */
+ smoothScroll.animateScroll = function ( toggle, anchor, options ) {
+
+ // Options and overrides
+ var overrides = getDataOptions( toggle ? toggle.getAttribute('data-options') : null );
+ var settings = extend( settings || defaults, options || {}, overrides ); // Merge user options with defaults
+ anchor = '#' + escapeCharacters(anchor.substr(1)); // Escape special characters and leading numbers
+
+ // Selectors and variables
+ var anchorElem = anchor === '#' ? root.document.documentElement : root.document.querySelector(anchor);
+ var startLocation = root.pageYOffset; // Current location on the page
+ if ( !fixedHeader ) { fixedHeader = root.document.querySelector('[data-scroll-header]'); } // Get the fixed header if not already set
+ if ( !headerHeight ) { headerHeight = getHeaderHeight( fixedHeader ); } // Get the height of a fixed header if one exists and not already set
+ var endLocation = getEndLocation( anchorElem, headerHeight, parseInt(settings.offset, 10) ); // Scroll to location
+ var animationInterval; // interval timer
+ var distance = endLocation - startLocation; // distance to travel
+ var documentHeight = getDocumentHeight();
+ var timeLapsed = 0;
+ var percentage, position;
+
+ // Update URL
+ updateUrl(anchor, settings.updateURL);
+
+ /**
+ * Stop the scroll animation when it reaches its target (or the bottom/top of page)
+ * @private
+ * @param {Number} position Current position on the page
+ * @param {Number} endLocation Scroll to location
+ * @param {Number} animationInterval How much to scroll on this loop
+ */
+ var stopAnimateScroll = function (position, endLocation, animationInterval) {
+ var currentLocation = root.pageYOffset;
+ if ( position == endLocation || currentLocation == endLocation || ( (root.innerHeight + currentLocation) >= documentHeight ) ) {
+ clearInterval(animationInterval);
+ anchorElem.focus();
+ settings.callback( toggle, anchor ); // Run callbacks after animation complete
+ }
+ };
+
+ /**
+ * Loop scrolling animation
+ * @private
+ */
+ var loopAnimateScroll = function () {
+ timeLapsed += 16;
+ percentage = ( timeLapsed / parseInt(settings.speed, 10) );
+ percentage = ( percentage > 1 ) ? 1 : percentage;
+ position = startLocation + ( distance * easingPattern(settings.easing, percentage) );
+ root.scrollTo( 0, Math.floor(position) );
+ stopAnimateScroll(position, endLocation, animationInterval);
+ };
+
+ /**
+ * Set interval timer
+ * @private
+ */
+ var startAnimateScroll = function () {
+ animationInterval = setInterval(loopAnimateScroll, 16);
+ };
+
+ /**
+ * Reset position to fix weird iOS bug
+ * @link https://github.com/cferdinandi/smooth-scroll/issues/45
+ */
+ if ( root.pageYOffset === 0 ) {
+ root.scrollTo( 0, 0 );
+ }
+
+ // Start scrolling animation
+ startAnimateScroll();
+
+ };
+
+ /**
+ * If smooth scroll element clicked, animate scroll
+ * @private
+ */
+ var eventHandler = function (event) {
+ var toggle = getClosest(event.target, '[data-scroll]');
+ if ( toggle && toggle.tagName.toLowerCase() === 'a' ) {
+ event.preventDefault(); // Prevent default click event
+ smoothScroll.animateScroll( toggle, toggle.hash, settings); // Animate scroll
+ }
+ };
+
+ /**
+ * On window scroll and resize, only run events at a rate of 15fps for better performance
+ * @private
+ * @param {Function} eventTimeout Timeout function
+ * @param {Object} settings
+ */
+ var eventThrottler = function (event) {
+ if ( !eventTimeout ) {
+ eventTimeout = setTimeout(function() {
+ eventTimeout = null; // Reset timeout
+ headerHeight = getHeaderHeight( fixedHeader ); // Get the height of a fixed header if one exists
+ }, 66);
+ }
+ };
+
+ /**
+ * Destroy the current initialization.
+ * @public
+ */
+ smoothScroll.destroy = function () {
+
+ // If plugin isn't already initialized, stop
+ if ( !settings ) return;
+
+ // Remove event listeners
+ root.document.removeEventListener( 'click', eventHandler, false );
+ root.removeEventListener( 'resize', eventThrottler, false );
+
+ // Reset varaibles
+ settings = null;
+ eventTimeout = null;
+ fixedHeader = null;
+ headerHeight = null;
+ };
+
+ /**
+ * Initialize Smooth Scroll
+ * @public
+ * @param {Object} options User settings
+ */
+ smoothScroll.init = function ( options ) {
+
+ // feature test
+ if ( !supports ) return;
+
+ // Destroy any existing initializations
+ smoothScroll.destroy();
+
+ // Selectors and variables
+ settings = extend( defaults, options || {} ); // Merge user options with defaults
+ fixedHeader = root.document.querySelector('[data-scroll-header]'); // Get the fixed header
+ headerHeight = getHeaderHeight( fixedHeader );
+
+ // When a toggle is clicked, run the click handler
+ root.document.addEventListener('click', eventHandler, false );
+ if ( fixedHeader ) { root.addEventListener( 'resize', eventThrottler, false ); }
+
+ };
+
+
+ //
+ // Public APIs
+ //
+
+ return smoothScroll;
+
+});
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/test/karma.conf.js b/static/website/bootstrap-css/bower_components/smooth-scroll/test/karma.conf.js
new file mode 100644
index 0000000..c140e5e
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/test/karma.conf.js
@@ -0,0 +1,26 @@
+module.exports = function (config) {
+ config.set({
+ basePath : '',
+ autoWatch : true,
+ frameworks: ['jasmine'],
+ browsers : ['PhantomJS'],
+ plugins : [
+ 'karma-spec-reporter',
+ 'karma-phantomjs-launcher',
+ 'karma-jasmine',
+ 'karma-coverage',
+ 'karma-htmlfile-reporter'
+ ],
+ reporters : ['spec', 'coverage', 'html'],
+ preprocessors: {
+ '../src/js/**/*.js': 'coverage'
+ },
+ coverageReporter: {
+ type : 'html',
+ dir : 'coverage/'
+ },
+ htmlReporter: {
+ outputFile: 'results/unit-tests.html'
+ }
+ });
+}; \ No newline at end of file
diff --git a/static/website/bootstrap-css/bower_components/smooth-scroll/test/spec/spec-smoothScroll.js b/static/website/bootstrap-css/bower_components/smooth-scroll/test/spec/spec-smoothScroll.js
new file mode 100644
index 0000000..a9f445d
--- /dev/null
+++ b/static/website/bootstrap-css/bower_components/smooth-scroll/test/spec/spec-smoothScroll.js
@@ -0,0 +1,131 @@
+describe('Smooth Scroll', function () {
+
+ //
+ // Helper Methods
+ //
+
+ /**
+ * Create a link element, add it to the body.
+ * @public
+ * @param {String} the href attribute of the new link
+ * @param {Boolean} whether to add data-scroll to the link or not
+ * @returns {Element}
+ */
+ var injectElem = function (href, smooth) {
+ var elt = document.createElement('a');
+ elt.href = href;
+ if (smooth) {
+ elt.setAttribute('data-scroll', true);
+ }
+ document.body.appendChild(elt);
+ return elt;
+ };
+
+ /**
+ * Simulate a click event.
+ * @public
+ * @param {Element} the element to simulate a click on
+ */
+ var simulateClick = function (elt) {
+ var click = document.createEvent('MouseEvents');
+ click.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
+ elt.dispatchEvent(click);
+ };
+
+ // A pattern for settings to validate their format.
+ var settingsStub = {
+ speed: jasmine.any(Number),
+ easing: jasmine.any(String),
+ offset: jasmine.any(Number),
+ updateURL: jasmine.any(Boolean),
+ callback: jasmine.any(Function)
+ };
+
+
+ //
+ // Init
+ //
+
+ describe('Should initialize plugin', function () {
+ it('Should export the smoothScroll module', function () {
+ expect(smoothScroll).toBeDefined();
+ });
+
+ it('Should expose public functions', function () {
+ expect(smoothScroll.init).toEqual(jasmine.any(Function));
+ expect(smoothScroll.destroy).toEqual(jasmine.any(Function));
+ expect(smoothScroll.animateScroll).toEqual(jasmine.any(Function));
+ });
+
+ it('Should add event listeners', function () {
+ spyOn(document, 'addEventListener');
+ smoothScroll.init();
+ expect(document.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), false);
+
+ spyOn(document, 'removeEventListener');
+ smoothScroll.destroy();
+ expect(document.removeEventListener).toHaveBeenCalledWith('click', jasmine.any(Function), false);
+ });
+ });
+
+
+ //
+ // Events
+ //
+
+ describe('Should animate scroll when anchor clicked', function () {
+ var elt = injectElem('#anchor', true);
+ document.body.setAttribute('id', 'anchor');
+
+ afterEach(function () {
+ smoothScroll.destroy();
+ });
+
+ it('Should trigger smooth scrolling on click', function () {
+ spyOn(smoothScroll, 'animateScroll');
+ smoothScroll.init();
+ simulateClick(elt);
+ expect(smoothScroll.animateScroll).toHaveBeenCalledWith(elt, '#anchor', jasmine.objectContaining(settingsStub));
+ });
+
+ it('Should do nothing if not initialized', function () {
+ spyOn(smoothScroll, 'animateScroll');
+ simulateClick(elt);
+ expect(smoothScroll.animateScroll).not.toHaveBeenCalled();
+ });
+
+ it('Should do nothing if destroyed', function () {
+ spyOn(smoothScroll, 'animateScroll');
+ smoothScroll.init();
+ smoothScroll.destroy();
+ simulateClick(elt);
+ expect(smoothScroll.animateScroll).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('Should run callbacks', function () {
+ var elt = injectElem('#anchor', true);
+ document.body.setAttribute('id', 'anchor');
+
+ // Generates a callback to test asynchronous calls.
+ var callback = function (eltVal, anchorVal, done) {
+ return function (toggle, anchor) {
+ expect(toggle).toBe(eltVal);
+ expect(anchor).toBe(anchorVal);
+ done();
+ };
+ };
+
+ afterEach(function () {
+ smoothScroll.destroy();
+ });
+
+ it('Should run callback', function (done) {
+ var settings = {
+ callback: callback(elt, '#anchor', done)
+ };
+ smoothScroll.init(settings);
+ simulateClick(elt);
+ });
+ });
+});