text: //
  // SmoothScroll for websites v1.4.4 (Balazs Galambosi)
  // http://www.smoothscroll.net/
  //
  // Licensed under the terms of the MIT license.
  //
  // You may use it in your theme if you credit me. 
  // It is also free to use on any individual website.
  //
  // Exception:
  // The only restriction is to not publish any  
  // extension for browsers or native application
  // without getting a written permission first.
  //
  
  (function () {
    
  // Scroll Variables (tweakable)
  var defaultOptions = {
  
      // Scrolling Core
      frameRate        : 150, // [Hz]
      animationTime    : 400, // [ms]
      stepSize         : 100, // [px]
  
      // Pulse (less tweakable)
      // ratio of "tail" to "acceleration"
      pulseAlgorithm   : true,
      pulseScale       : 4,
      pulseNormalize   : 1,
  
      // Acceleration
      accelerationDelta : 50,  // 50
      accelerationMax   : 3,   // 3
  
      // Keyboard Settings
      keyboardSupport   : true,  // option
      arrowScroll       : 50,    // [px]
  
      // Other
      touchpadSupport   : false, // ignore touchpad by default
      fixedBackground   : true, 
      excluded          : ''    
  };
  
  var options = defaultOptions;
  
  
  // Other Variables
  var isExcluded = false;
  var isFrame = false;
  var direction = { x: 0, y: 0 };
  var initDone  = false;
  var root = document.documentElement;
  var activeElement;
  var observer;
  var refreshSize;
  var deltaBuffer = [];
  var isMac = /^Mac/.test(navigator.platform);
  
  var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32, 
              pageup: 33, pagedown: 34, end: 35, home: 36 };
  var arrowKeys = { 37: 1, 38: 1, 39: 1, 40: 1 };
  
  /***********************************************
   * INITIALIZE
   ***********************************************/
  
  /**
   * Tests if smooth scrolling is allowed. Shuts down everything if not.
   */
  function initTest() {
      if (options.keyboardSupport) {
          addEvent('keydown', keydown);
      }
  }
  
  /**
   * Sets up scrolls array, determines if frames are involved.
   */
  function init() {
    
      if (initDone || !document.body) return;
  
      initDone = true;
  
      var body = document.body;
      var html = document.documentElement;
      var windowHeight = window.innerHeight; 
      var scrollHeight = body.scrollHeight;
      
      // check compat mode for root element
      root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;
      activeElement = body;
      
      initTest();
  
      // Checks if this script is running in a frame
      if (top != self) {
          isFrame = true;
      }
  
      /**
       * Please duplicate this radar for a Safari fix! 
       * rdar://22376037
       * https://openradar.appspot.com/radar?id=4965070979203072
       * 
       * Only applies to Safari now, Chrome fixed it in v45:
       * This fixes a bug where the areas left and right to 
       * the content does not trigger the onmousewheel event
       * on some pages. e.g.: html, body { height: 100% }
       */
      else if (scrollHeight > windowHeight &&
              (body.offsetHeight <= windowHeight || 
               html.offsetHeight <= windowHeight)) {
  
          var fullPageElem = document.createElement('div');
          fullPageElem.style.cssText = 'position:absolute; z-index:-10000; ' +
                                       'top:0; left:0; right:0; height:' + 
                                        root.scrollHeight + 'px';
          document.body.appendChild(fullPageElem);
          
          // DOM changed (throttled) to fix height
          var pendingRefresh;
          refreshSize = function () {
              if (pendingRefresh) return; // could also be: clearTimeout(pendingRefresh);
              pendingRefresh = setTimeout(function () {
                  if (isExcluded) return; // could be running after cleanup
                  fullPageElem.style.height = '0';
                  fullPageElem.style.height = root.scrollHeight + 'px';
                  pendingRefresh = null;
              }, 500); // act rarely to stay fast
          };
    
          setTimeout(refreshSize, 10);
  
          addEvent('resize', refreshSize);
  
          // TODO: attributeFilter?
          var config = {
              attributes: true, 
              childList: true, 
              characterData: false 
              // subtree: true
          };
  
          observer = new MutationObserver(refreshSize);
          observer.observe(body, config);
  
          if (root.offsetHeight <= windowHeight) {
              var clearfix = document.createElement('div');   
              clearfix.style.clear = 'both';
              body.appendChild(clearfix);
          }
      }
  
      // disable fixed background
      if (!options.fixedBackground && !isExcluded) {
          body.style.backgroundAttachment = 'scroll';
          html.style.backgroundAttachment = 'scroll';
      }
  }
  
  /**
   * Removes event listeners and other traces left on the page.
   */
  function cleanup() {
      observer && observer.disconnect();
      removeEvent(wheelEvent, wheel);
      removeEvent('mousedown', mousedown);
      removeEvent('keydown', keydown);
      removeEvent('resize', refreshSize);
      removeEvent('load', init);
  }
  
  
  /************************************************
   * SCROLLING 
   ************************************************/
   
  var que = [];
  var pending = false;
  var lastScroll = Date.now();
  
  /**
   * Pushes scroll actions to the scrolling queue.
   */
  function scrollArray(elem, left, top) {
      
      directionCheck(left, top);
  
      if (options.accelerationMax != 1) {
          var now = Date.now();
          var elapsed = now - lastScroll;
          if (elapsed < options.accelerationDelta) {
              var factor = (1 + (50 / elapsed)) / 2;
              if (factor > 1) {
                  factor = Math.min(factor, options.accelerationMax);
                  left *= factor;
                  top  *= factor;
              }
          }
          lastScroll = Date.now();
      }          
      
      // push a scroll command
      que.push({
          x: left, 
          y: top, 
          lastX: (left < 0) ? 0.99 : -0.99,
          lastY: (top  < 0) ? 0.99 : -0.99, 
          start: Date.now()
      });
          
      // don't act if there's a pending queue
      if (pending) {
          return;
      }  
  
      var scrollWindow = (elem === document.body);
      
      var step = function (time) {
          
          var now = Date.now();
          var scrollX = 0;
          var scrollY = 0; 
      
          for (var i = 0; i < que.length; i++) {
              
              var item = que[i];
              var elapsed  = now - item.start;
              var finished = (elapsed >= options.animationTime);
              
              // scroll position: [0, 1]
              var position = (finished) ? 1 : elapsed / options.animationTime;
              
              // easing [optional]
              if (options.pulseAlgorithm) {
                  position = pulse(position);
              }
              
              // only need the difference
              var x = (item.x * position - item.lastX) >> 0;
              var y = (item.y * position - item.lastY) >> 0;
              
              // add this to the total scrolling
              scrollX += x;
              scrollY += y;            
              
              // update last values
              item.lastX += x;
              item.lastY += y;
          
              // delete and step back if it's over
              if (finished) {
                  que.splice(i, 1); i--;
              }           
          }
  
          // scroll left and top
          if (scrollWindow) {
              window.scrollBy(scrollX, scrollY);
          } 
          else {
              if (scrollX) elem.scrollLeft += scrollX;
              if (scrollY) elem.scrollTop  += scrollY;                    
          }
          
          // clean up if there's nothing left to do
          if (!left && !top) {
              que = [];
          }
          
          if (que.length) { 
              requestFrame(step, elem, (1000 / options.frameRate + 1)); 
          } else { 
              pending = false;
          }
      };
      
      // start a new queue of actions
      requestFrame(step, elem, 0);
      pending = true;
  }
  
  
  /***********************************************
   * EVENTS
   ***********************************************/
  
  /**
   * Mouse wheel handler.
   * @param {Object} event
   */
  function wheel(event) {
  
      if (!initDone) {
          init();
      }
      
      var target = event.target;
      var overflowing = overflowingAncestor(target);
  
      // use default if there's no overflowing
      // element or default action is prevented   
      // or it's a zooming event with CTRL 
      if (!overflowing || event.defaultPrevented || event.ctrlKey) {
          return true;
      }
      
      // leave embedded content alone (flash & pdf)
      if (isNodeName(activeElement, 'embed') || 
         (isNodeName(target, 'embed') && /\.pdf/i.test(target.src)) ||
          isNodeName(activeElement, 'object') ||
          target.shadowRoot) {
          return true;
      }
  
      var deltaX = -event.wheelDeltaX || event.deltaX || 0;
      var deltaY = -event.wheelDeltaY || event.deltaY || 0;
      
      if (isMac) {
          if (event.wheelDeltaX && isDivisible(event.wheelDeltaX, 120)) {
              deltaX = -120 * (event.wheelDeltaX / Math.abs(event.wheelDeltaX));
          }
          if (event.wheelDeltaY && isDivisible(event.wheelDeltaY, 120)) {
              deltaY = -120 * (event.wheelDeltaY / Math.abs(event.wheelDeltaY));
          }
      }
      
      // use wheelDelta if deltaX/Y is not available
      if (!deltaX && !deltaY) {
          deltaY = -event.wheelDelta || 0;
      }
  
      // line based scrolling (Firefox mostly)
      if (event.deltaMode === 1) {
          deltaX *= 40;
          deltaY *= 40;
      }
      
      // check if it's a touchpad scroll that should be ignored
      if (!options.touchpadSupport && isTouchpad(deltaY)) {
          return true;
      }
  
      // scale by step size
      // delta is 120 most of the time
      // synaptics seems to send 1 sometimes
      if (Math.abs(deltaX) > 1.2) {
          deltaX *= options.stepSize / 120;
      }
      if (Math.abs(deltaY) > 1.2) {
          deltaY *= options.stepSize / 120;
      }
      
      scrollArray(overflowing, deltaX, deltaY);
      event.preventDefault();
      scheduleClearCache();
  }
  
  /**
   * Keydown event handler.
   * @param {Object} event
   */
  function keydown(event) {
  
      var target   = event.target;
      var modifier = event.ctrlKey || event.altKey || event.metaKey || 
                    (event.shiftKey && event.keyCode !== key.spacebar);
      
      // our own tracked active element could've been removed from the DOM
      if (!document.body.contains(activeElement)) {
          activeElement = document.activeElement;
      }
  
      // do nothing if user is editing text
      // or using a modifier key (except shift)
      // or in a dropdown
      // or inside interactive elements
      var inputNodeNames = /^(textarea|select|embed|object)$/i;
      var buttonTypes = /^(button|submit|radio|checkbox|file|color|image)$/i;
      if ( event.defaultPrevented ||
           inputNodeNames.test(target.nodeName) ||
           isNodeName(target, 'input') && !buttonTypes.test(target.type) ||
           isNodeName(activeElement, 'video') ||
           isInsideYoutubeVideo(event) ||
           target.isContentEditable || 
           modifier ) {
        return true;
      }
  
      // [spacebar] should trigger button press, leave it alone
      if ((isNodeName(target, 'button') ||
           isNodeName(target, 'input') && buttonTypes.test(target.type)) &&
          event.keyCode === key.spacebar) {
        return true;
      }
  
      // [arrwow keys] on radio buttons should be left alone
      if (isNodeName(target, 'input') && target.type == 'radio' &&
          arrowKeys[event.keyCode])  {
        return true;
      }
      
      var shift, x = 0, y = 0;
      var elem = overflowingAncestor(activeElement);
      var clientHeight = elem.clientHeight;
  
      if (elem == document.body) {
          clientHeight = window.innerHeight;
      }
  
      switch (event.keyCode) {
          case key.up:
              y = -options.arrowScroll;
              break;
          case key.down:
              y = options.arrowScroll;
              break;         
          case key.spacebar: // (+ shift)
              shift = event.shiftKey ? 1 : -1;
              y = -shift * clientHeight * 0.9;
              break;
          case key.pageup:
              y = -clientHeight * 0.9;
              break;
          case key.pagedown:
              y = clientHeight * 0.9;
              break;
          case key.home:
              y = -elem.scrollTop;
              break;
          case key.end:
              var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
              y = (damt > 0) ? damt+10 : 0;
              break;
          case key.left:
              x = -options.arrowScroll;
              break;
          case key.right:
              x = options.arrowScroll;
              break;            
          default:
              return true; // a key we don't care about
      }
  
      scrollArray(elem, x, y);
      event.preventDefault();
      scheduleClearCache();
  }
  
  /**
   * Mousedown event only for updating activeElement
   */
  function mousedown(event) {
      activeElement = event.target;
  }
  
  
  /***********************************************
   * OVERFLOW
   ***********************************************/
  
  var uniqueID = (function () {
      var i = 0;
      return function (el) {
          return el.uniqueID || (el.uniqueID = i++);
      };
  })();
  
  var cache = {}; // cleared out after a scrolling session
  var clearCacheTimer;
  
  //setInterval(function () { cache = {}; }, 10 * 1000);
  
  function scheduleClearCache() {
      clearTimeout(clearCacheTimer);
      clearCacheTimer = setInterval(function () { cache = {}; }, 1*1000);
  }
  
  function setCache(elems, overflowing) {
      for (var i = elems.length; i--;)
          cache[uniqueID(elems[i])] = overflowing;
      return overflowing;
  }
  
  //  (body)                (root)
  //         | hidden | visible | scroll |  auto  |
  // hidden  |   no   |    no   |   YES  |   YES  |
  // visible |   no   |   YES   |   YES  |   YES  |
  // scroll  |   no   |   YES   |   YES  |   YES  |
  // auto    |   no   |   YES   |   YES  |   YES  |
  
  function overflowingAncestor(el) {
      var elems = [];
      var body = document.body;
      var rootScrollHeight = root.scrollHeight;
      do {
          var cached = cache[uniqueID(el)];
          if (cached) {
              return setCache(elems, cached);
          }
          elems.push(el);
          if (rootScrollHeight === el.scrollHeight) {
              var topOverflowsNotHidden = overflowNotHidden(root) && overflowNotHidden(body);
              var isOverflowCSS = topOverflowsNotHidden || overflowAutoOrScroll(root);
              if (isFrame && isContentOverflowing(root) || 
                 !isFrame && isOverflowCSS) {
                  return setCache(elems, getScrollRoot()); 
              }
          } else if (isContentOverflowing(el) && overflowAutoOrScroll(el)) {
              return setCache(elems, el);
          }
      } while (el = el.parentElement);
  }
  
  function isContentOverflowing(el) {
      return (el.clientHeight + 10 < el.scrollHeight);
  }
  
  // typically for <body> and <html>
  function overflowNotHidden(el) {
      var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
      return (overflow !== 'hidden');
  }
  
  // for all other elements
  function overflowAutoOrScroll(el) {
      var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
      return (overflow === 'scroll' || overflow === 'auto');
  }
  
  
  /***********************************************
   * HELPERS
   ***********************************************/
  
  function addEvent(type, fn) {
      window.addEventListener(type, fn, false);
  }
  
  function removeEvent(type, fn) {
      window.removeEventListener(type, fn, false);  
  }
  
  function isNodeName(el, tag) {
      return (el.nodeName||'').toLowerCase() === tag.toLowerCase();
  }
  
  function directionCheck(x, y) {
      x = (x > 0) ? 1 : -1;
      y = (y > 0) ? 1 : -1;
      if (direction.x !== x || direction.y !== y) {
          direction.x = x;
          direction.y = y;
          que = [];
          lastScroll = 0;
      }
  }
  
  var deltaBufferTimer;
  
  if (window.localStorage && localStorage.SS_deltaBuffer) {
      deltaBuffer = localStorage.SS_deltaBuffer.split(',');
  }
  
  function isTouchpad(deltaY) {
      if (!deltaY) return;
      if (!deltaBuffer.length) {
          deltaBuffer = [deltaY, deltaY, deltaY];
      }
      deltaY = Math.abs(deltaY);
      deltaBuffer.push(deltaY);
      deltaBuffer.shift();
      clearTimeout(deltaBufferTimer);
      deltaBufferTimer = setTimeout(function () {
          if (window.localStorage) {
              localStorage.SS_deltaBuffer = deltaBuffer.join(',');
          }
      }, 1000);
      return !allDeltasDivisableBy(120) && !allDeltasDivisableBy(100);
  } 
  
  function isDivisible(n, divisor) {
      return (Math.floor(n / divisor) == n / divisor);
  }
  
  function allDeltasDivisableBy(divisor) {
      return (isDivisible(deltaBuffer[0], divisor) &&
              isDivisible(deltaBuffer[1], divisor) &&
              isDivisible(deltaBuffer[2], divisor));
  }
  
  function isInsideYoutubeVideo(event) {
      var elem = event.target;
      var isControl = false;
      if (document.URL.indexOf ('www.youtube.com/watch') != -1) {
          do {
              isControl = (elem.classList && 
                           elem.classList.contains('html5-video-controls'));
              if (isControl) break;
          } while (elem = elem.parentNode);
      }
      return isControl;
  }
  
  var requestFrame = (function () {
        return (window.requestAnimationFrame       || 
                window.webkitRequestAnimationFrame || 
                window.mozRequestAnimationFrame    ||
                function (callback, element, delay) {
                   window.setTimeout(callback, delay || (1000/60));
               });
  })();
  
  var MutationObserver = (window.MutationObserver || 
                          window.WebKitMutationObserver ||
                          window.MozMutationObserver);  
  
  var getScrollRoot = (function() {
    var SCROLL_ROOT;
    return function() {
      if (!SCROLL_ROOT) {
        var dummy = document.createElement('div');
        dummy.style.cssText = 'height:10000px;width:1px;';
        document.body.appendChild(dummy);
        var bodyScrollTop  = document.body.scrollTop;
        var docElScrollTop = document.documentElement.scrollTop;
        window.scrollBy(0, 3);
        if (document.body.scrollTop != bodyScrollTop)
          (SCROLL_ROOT = document.body);
        else 
          (SCROLL_ROOT = document.documentElement);
        window.scrollBy(0, -3);
        document.body.removeChild(dummy);
      }
      return SCROLL_ROOT;
    };
  })();
  
  
  /***********************************************
   * PULSE (by Michael Herf)
   ***********************************************/
   
  /**
   * Viscous fluid with a pulse for part and decay for the rest.
   * - Applies a fixed force over an interval (a damped acceleration), and
   * - Lets the exponential bleed away the velocity over a longer interval
   * - Michael Herf, http://stereopsis.com/stopping/
   */
  function pulse_(x) {
      var val, start, expx;
      // test
      x = x * options.pulseScale;
      if (x < 1) { // acceleartion
          val = x - (1 - Math.exp(-x));
      } else {     // tail
          // the previous animation ended here:
          start = Math.exp(-1);
          // simple viscous drag
          x -= 1;
          expx = 1 - Math.exp(-x);
          val = start + (expx * (1 - start));
      }
      return val * options.pulseNormalize;
  }
  
  function pulse(x) {
      if (x >= 1) return 1;
      if (x <= 0) return 0;
  
      if (options.pulseNormalize == 1) {
          options.pulseNormalize /= pulse_(1);
      }
      return pulse_(x);
  }
  
  
  /***********************************************
   * FIRST RUN
   ***********************************************/
  
  var userAgent = window.navigator.userAgent;
  var isEdge    = /Edge/.test(userAgent); // thank you MS
  var isChrome  = /chrome/i.test(userAgent) && !isEdge; 
  var isSafari  = /safari/i.test(userAgent) && !isEdge; 
  var isMobile  = /mobile/i.test(userAgent);
  var isIEWin7  = /Windows NT 6.1/i.test(userAgent) && /rv:11/i.test(userAgent);
  var isEnabledForBrowser = (isChrome || isSafari || isIEWin7) && !isMobile;
  
  var wheelEvent;
  if ('onwheel' in document.createElement('div'))
      wheelEvent = 'wheel';
  else if ('onmousewheel' in document.createElement('div'))
      wheelEvent = 'mousewheel';
  
  if (wheelEvent && isEnabledForBrowser) {
      addEvent(wheelEvent, wheel);
      addEvent('mousedown', mousedown);
      addEvent('load', init);
  }
  
  
  /***********************************************
   * PUBLIC INTERFACE
   ***********************************************/
  
  function SmoothScroll(optionsToSet) {
      for (var key in optionsToSet)
          if (defaultOptions.hasOwnProperty(key)) 
              options[key] = optionsToSet[key];
  }
  SmoothScroll.destroy = cleanup;
  
  if (window.SmoothScrollOptions) // async API
      SmoothScroll(window.SmoothScrollOptions);
  
  if (typeof define === 'function' && define.amd)
      define(function() {
          return SmoothScroll;
      });
  else if ('object' == typeof exports)
      module.exports = SmoothScroll;
  else
      window.SmoothScroll = SmoothScroll;
  
  })();