intro.js update and according changes to source (fixes #109)

Change-Id: I52e439e64d39e44f2c8b3dd5d2d37e0d13d48743
diff --git a/dev/js/lib/intro.js b/dev/js/lib/intro.js
index 76f0116..cc6820b 100644
--- a/dev/js/lib/intro.js
+++ b/dev/js/lib/intro.js
@@ -1,1531 +1,73 @@
-/**
- * Intro.js v2.9.3
- * https://github.com/usablica/intro.js
+/*!
+ * Intro.js v4.2.2
+ * https://introjs.com
  *
- * Copyright (C) 2017 Afshin Mehrabani (@afshinmeh)
+ * Copyright (C) 2012-2021 Afshin Mehrabani (@afshinmeh).
+ * https://raw.githubusercontent.com/usablica/intro.js/master/license.md
+ *
+ * Date: Fri, 27 Aug 2021 12:07:05 GMT
  */
 
-(function(f) {
-    if (typeof exports === "object" && typeof module !== "undefined") {
-        module.exports = f();
-        // deprecated function
-        // @since 2.8.0
-        module.exports.introJs = function () {
-          console.warn('Deprecated: please use require("intro.js") directly, instead of the introJs method of the function');
-          // introJs()
-          return f().apply(this, arguments);
-        };
-    } else if (typeof define === "function" && define.amd) {
-        define([], f);
-    } else {
-        var g;
-        if (typeof window !== "undefined") {
-            g = window;
-        } else if (typeof global !== "undefined") {
-            g = global;
-        } else if (typeof self !== "undefined") {
-            g = self;
-        } else {
-            g = this;
-        }
-        g.introJs = f();
-    }
-})(function () {
-  //Default config/variables
-  var VERSION = '2.9.3';
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+  typeof define === 'function' && define.amd ? define(factory) :
+  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.introJs = factory());
+}(this, (function () { 'use strict';
 
-  /**
-   * IntroJs main class
-   *
-   * @class IntroJs
-   */
-  function IntroJs(obj) {
-    this._targetElement = obj;
-    this._introItems = [];
+  function _typeof(obj) {
+    "@babel/helpers - typeof";
 
-    this._options = {
-      /* Next button label in tooltip box */
-      nextLabel: 'Next →',
-      /* Previous button label in tooltip box */
-      prevLabel: '← Back',
-      /* Skip button label in tooltip box */
-      skipLabel: 'Skip',
-      /* Done button label in tooltip box */
-      doneLabel: 'Done',
-      /* Hide previous button in the first step? Otherwise, it will be disabled button. */
-      hidePrev: false,
-      /* Hide next button in the last step? Otherwise, it will be disabled button. */
-      hideNext: false,
-      /* Default tooltip box position */
-      tooltipPosition: 'bottom',
-      /* Next CSS class for tooltip boxes */
-      tooltipClass: '',
-      /* CSS class that is added to the helperLayer */
-      highlightClass: '',
-      /* Close introduction when pressing Escape button? */
-      exitOnEsc: true,
-      /* Close introduction when clicking on overlay layer? */
-      exitOnOverlayClick: true,
-      /* Show step numbers in introduction? */
-      showStepNumbers: true,
-      /* Let user use keyboard to navigate the tour? */
-      keyboardNavigation: true,
-      /* Show tour control buttons? */
-      showButtons: true,
-      /* Show tour bullets? */
-      showBullets: true,
-      /* Show tour progress? */
-      showProgress: false,
-      /* Scroll to highlighted element? */
-      scrollToElement: true,
-      /*
-       * Should we scroll the tooltip or target element?
-       *
-       * Options are: 'element' or 'tooltip'
-       */
-      scrollTo: 'element',
-      /* Padding to add after scrolling when element is not in the viewport (in pixels) */
-      scrollPadding: 30,
-      /* Set the overlay opacity */
-      overlayOpacity: 0.8,
-      /* Precedence of positions, when auto is enabled */
-      positionPrecedence: ["bottom", "top", "right", "left"],
-      /* Disable an interaction with element? */
-      disableInteraction: false,
-      /* Set how much padding to be used around helper element */
-      helperElementPadding: 10,
-      /* Default hint position */
-      hintPosition: 'top-middle',
-      /* Hint button label */
-      hintButtonLabel: 'Got it',
-      /* Adding animation to hints? */
-      hintAnimation: true,
-      /* additional classes to put on the buttons */
-      buttonClass: "introjs-button"
-    };
-  }
-
-  /**
-   * Initiate a new introduction/guide from an element in the page
-   *
-   * @api private
-   * @method _introForElement
-   * @param {Object} targetElm
-   * @param {String} group
-   * @returns {Boolean} Success or not?
-   */
-  function _introForElement(targetElm, group) {
-    var allIntroSteps = targetElm.querySelectorAll("*[data-intro]"),
-        introItems = [];
-
-    if (this._options.steps) {
-      //use steps passed programmatically
-      _forEach(this._options.steps, function (step) {
-        var currentItem = _cloneObject(step);
-
-        //set the step
-        currentItem.step = introItems.length + 1;
-
-        //use querySelector function only when developer used CSS selector
-        if (typeof (currentItem.element) === 'string') {
-          //grab the element with given selector from the page
-          currentItem.element = document.querySelector(currentItem.element);
-        }
-
-        //intro without element
-        if (typeof (currentItem.element) === 'undefined' || currentItem.element === null) {
-          var floatingElementQuery = document.querySelector(".introjsFloatingElement");
-
-          if (floatingElementQuery === null) {
-            floatingElementQuery = document.createElement('div');
-            floatingElementQuery.className = 'introjsFloatingElement';
-
-            document.body.appendChild(floatingElementQuery);
-          }
-
-          currentItem.element  = floatingElementQuery;
-          currentItem.position = 'floating';
-        }
-
-        currentItem.scrollTo = currentItem.scrollTo || this._options.scrollTo;
-
-        if (typeof (currentItem.disableInteraction) === 'undefined') {
-          currentItem.disableInteraction = this._options.disableInteraction;
-        }
-
-        if (currentItem.element !== null) {
-          introItems.push(currentItem);
-        }        
-      }.bind(this));
-
-    } else {
-      //use steps from data-* annotations
-      var elmsLength = allIntroSteps.length;
-      var disableInteraction;
-      
-      //if there's no element to intro
-      if (elmsLength < 1) {
-        return false;
-      }
-
-      _forEach(allIntroSteps, function (currentElement) {
-        
-        // PR #80
-        // start intro for groups of elements
-        if (group && (currentElement.getAttribute("data-intro-group") !== group)) {
-          return;
-        }
-
-        // skip hidden elements
-        if (currentElement.style.display === 'none') {
-          return;
-        }
-
-        var step = parseInt(currentElement.getAttribute('data-step'), 10);
-
-        if (typeof (currentElement.getAttribute('data-disable-interaction')) !== 'undefined') {
-          disableInteraction = !!currentElement.getAttribute('data-disable-interaction');
-        } else {
-          disableInteraction = this._options.disableInteraction;
-        }
-
-        if (step > 0) {
-          introItems[step - 1] = {
-            element: currentElement,
-            intro: currentElement.getAttribute('data-intro'),
-            step: parseInt(currentElement.getAttribute('data-step'), 10),
-            tooltipClass: currentElement.getAttribute('data-tooltipclass'),
-            highlightClass: currentElement.getAttribute('data-highlightclass'),
-            position: currentElement.getAttribute('data-position') || this._options.tooltipPosition,
-            scrollTo: currentElement.getAttribute('data-scrollto') || this._options.scrollTo,
-            disableInteraction: disableInteraction
-          };
-        }
-      }.bind(this));
-
-      //next add intro items without data-step
-      //todo: we need a cleanup here, two loops are redundant
-      var nextStep = 0;
-
-      _forEach(allIntroSteps, function (currentElement) {
-        
-        // PR #80
-        // start intro for groups of elements
-        if (group && (currentElement.getAttribute("data-intro-group") !== group)) {
-          return;
-        }
-        
-        if (currentElement.getAttribute('data-step') === null) {
-
-          while (true) {
-            if (typeof introItems[nextStep] === 'undefined') {
-              break;
-            } else {
-              nextStep++;
-            }
-          } 
-
-          if (typeof (currentElement.getAttribute('data-disable-interaction')) !== 'undefined') {
-            disableInteraction = !!currentElement.getAttribute('data-disable-interaction');
-          } else {
-            disableInteraction = this._options.disableInteraction;
-          }
-
-          introItems[nextStep] = {
-            element: currentElement,
-            intro: currentElement.getAttribute('data-intro'),
-            step: nextStep + 1,
-            tooltipClass: currentElement.getAttribute('data-tooltipclass'),
-            highlightClass: currentElement.getAttribute('data-highlightclass'),
-            position: currentElement.getAttribute('data-position') || this._options.tooltipPosition,
-            scrollTo: currentElement.getAttribute('data-scrollto') || this._options.scrollTo,
-            disableInteraction: disableInteraction
-          };
-        }
-      }.bind(this));
-    }
-
-    //removing undefined/null elements
-    var tempIntroItems = [];
-    for (var z = 0; z < introItems.length; z++) {
-      if (introItems[z]) {
-        // copy non-falsy values to the end of the array
-        tempIntroItems.push(introItems[z]);  
-      } 
-    }
-
-    introItems = tempIntroItems;
-
-    //Ok, sort all items with given steps
-    introItems.sort(function (a, b) {
-      return a.step - b.step;
-    });
-
-    //set it to the introJs object
-    this._introItems = introItems;
-
-    //add overlay layer to the page
-    if(_addOverlayLayer.call(this, targetElm)) {
-      //then, start the show
-      _nextStep.call(this);
-
-      if (this._options.keyboardNavigation) {
-        DOMEvent.on(window, 'keydown', _onKeyDown, this, true);
-      }
-      //for window resize
-      DOMEvent.on(window, 'resize', _onResize, this, true);
-    }
-    return false;
-  }
-
-  function _onResize () {
-    this.refresh.call(this);
-  }
-
-  /**
-  * on keyCode:
-  * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
-  * This feature has been removed from the Web standards.
-  * Though some browsers may still support it, it is in
-  * the process of being dropped.
-  * Instead, you should use KeyboardEvent.code,
-  * if it's implemented.
-  *
-  * jQuery's approach is to test for
-  *   (1) e.which, then
-  *   (2) e.charCode, then
-  *   (3) e.keyCode
-  * https://github.com/jquery/jquery/blob/a6b0705294d336ae2f63f7276de0da1195495363/src/event.js#L638
-  *
-  * @param type var
-  * @return type
-  */
-  function _onKeyDown (e) {
-    var code = (e.code === null) ? e.which : e.code;
-
-    // if code/e.which is null
-    if (code === null) {
-      code = (e.charCode === null) ? e.keyCode : e.charCode;
-    }
-    
-    if ((code === 'Escape' || code === 27) && this._options.exitOnEsc === true) {
-      //escape key pressed, exit the intro
-      //check if exit callback is defined
-      _exitIntro.call(this, this._targetElement);
-    } else if (code === 'ArrowLeft' || code === 37) {
-      //left arrow
-      _previousStep.call(this);
-    } else if (code === 'ArrowRight' || code === 39) {
-      //right arrow
-      _nextStep.call(this);
-    } else if (code === 'Enter' || code === 13) {
-      //srcElement === ie
-      var target = e.target || e.srcElement;
-      if (target && target.className.match('introjs-prevbutton')) {
-        //user hit enter while focusing on previous button
-        _previousStep.call(this);
-      } else if (target && target.className.match('introjs-skipbutton')) {
-        //user hit enter while focusing on skip button
-        if (this._introItems.length - 1 === this._currentStep && typeof (this._introCompleteCallback) === 'function') {
-            this._introCompleteCallback.call(this);
-        }
-
-        _exitIntro.call(this, this._targetElement);
-      } else if (target && target.getAttribute('data-stepnumber')) {
-        // user hit enter while focusing on step bullet
-        target.click();
-      } else {
-        //default behavior for responding to enter
-        _nextStep.call(this);
-      }
-
-      //prevent default behaviour on hitting Enter, to prevent steps being skipped in some browsers
-      if(e.preventDefault) {
-        e.preventDefault();
-      } else {
-        e.returnValue = false;
-      }
-    }
-  }
-
- /*
-   * makes a copy of the object
-   * @api private
-   * @method _cloneObject
-  */
-  function _cloneObject(object) {
-      if (object === null || typeof (object) !== 'object' || typeof (object.nodeType) !== 'undefined') {
-        return object;
-      }
-      var temp = {};
-      for (var key in object) {
-        if (typeof(window.jQuery) !== 'undefined' && object[key] instanceof window.jQuery) {
-          temp[key] = object[key];
-        } else {
-          temp[key] = _cloneObject(object[key]);
-        }
-      }
-      return temp;
-  }
-  /**
-   * Go to specific step of introduction
-   *
-   * @api private
-   * @method _goToStep
-   */
-  function _goToStep(step) {
-    //because steps starts with zero
-    this._currentStep = step - 2;
-    if (typeof (this._introItems) !== 'undefined') {
-      _nextStep.call(this);
-    }
-  }
-
-  /**
-   * Go to the specific step of introduction with the explicit [data-step] number
-   *
-   * @api private
-   * @method _goToStepNumber
-   */
-  function _goToStepNumber(step) {
-    this._currentStepNumber = step;
-    if (typeof (this._introItems) !== 'undefined') {
-      _nextStep.call(this);
-    }
-  }
-
-  /**
-   * Go to next step on intro
-   *
-   * @api private
-   * @method _nextStep
-   */
-  function _nextStep() {
-    this._direction = 'forward';
-
-    if (typeof (this._currentStepNumber) !== 'undefined') {
-      _forEach(this._introItems, function (item, i) {
-        if( item.step === this._currentStepNumber ) {
-          this._currentStep = i - 1;
-          this._currentStepNumber = undefined;
-        }
-      }.bind(this));
-    }
-
-    if (typeof (this._currentStep) === 'undefined') {
-      this._currentStep = 0;
-    } else {
-      ++this._currentStep;
-    }
-
-    var nextStep = this._introItems[this._currentStep];
-    var continueStep = true;
-
-    if (typeof (this._introBeforeChangeCallback) !== 'undefined') {
-      continueStep = this._introBeforeChangeCallback.call(this, nextStep.element);
-    }
-
-    // if `onbeforechange` returned `false`, stop displaying the element
-    if (continueStep === false) {
-      --this._currentStep;
-      return false;
-    }
-
-    if ((this._introItems.length) <= this._currentStep) {
-      //end of the intro
-      //check if any callback is defined
-      if (typeof (this._introCompleteCallback) === 'function') {
-        this._introCompleteCallback.call(this);
-      }
-      _exitIntro.call(this, this._targetElement);
-      return;
-    }
-
-    _showElement.call(this, nextStep);
-  }
-
-  /**
-   * Go to previous step on intro
-   *
-   * @api private
-   * @method _previousStep
-   */
-  function _previousStep() {
-    this._direction = 'backward';
-
-    if (this._currentStep === 0) {
-      return false;
-    }
-
-    --this._currentStep;
-
-    var nextStep = this._introItems[this._currentStep];
-    var continueStep = true;
-
-    if (typeof (this._introBeforeChangeCallback) !== 'undefined') {
-      continueStep = this._introBeforeChangeCallback.call(this, nextStep.element);
-    }
-
-    // if `onbeforechange` returned `false`, stop displaying the element
-    if (continueStep === false) {
-      ++this._currentStep;
-      return false;
-    }
-
-    _showElement.call(this, nextStep);
-  }
-
-  /**
-   * Update placement of the intro objects on the screen
-   * @api private
-   */
-  function _refresh() {
-    // re-align intros
-    _setHelperLayerPosition.call(this, document.querySelector('.introjs-helperLayer'));
-    _setHelperLayerPosition.call(this, document.querySelector('.introjs-tooltipReferenceLayer'));
-    _setHelperLayerPosition.call(this, document.querySelector('.introjs-disableInteraction'));
-
-    // re-align tooltip
-    if(this._currentStep !== undefined && this._currentStep !== null) {
-      var oldHelperNumberLayer = document.querySelector('.introjs-helperNumberLayer'),
-        oldArrowLayer        = document.querySelector('.introjs-arrow'),
-        oldtooltipContainer  = document.querySelector('.introjs-tooltip');
-      _placeTooltip.call(this, this._introItems[this._currentStep].element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer);
-    }
-
-    //re-align hints
-    _reAlignHints.call(this);
-    return this;
-  }
-
-  /**
-   * Exit from intro
-   *
-   * @api private
-   * @method _exitIntro
-   * @param {Object} targetElement
-   * @param {Boolean} force - Setting to `true` will skip the result of beforeExit callback
-   */
-  function _exitIntro(targetElement, force) {
-    var continueExit = true;
-
-    // calling onbeforeexit callback
-    //
-    // If this callback return `false`, it would halt the process
-    if (this._introBeforeExitCallback !== undefined) {
-      continueExit = this._introBeforeExitCallback.call(this);
-    }
-
-    // skip this check if `force` parameter is `true`
-    // otherwise, if `onbeforeexit` returned `false`, don't exit the intro
-    if (!force && continueExit === false) return;
-
-    //remove overlay layers from the page
-    var overlayLayers = targetElement.querySelectorAll('.introjs-overlay');
-
-    if (overlayLayers && overlayLayers.length) {
-      _forEach(overlayLayers, function (overlayLayer) {
-        overlayLayer.style.opacity = 0;
-        window.setTimeout(function () {
-          if (this.parentNode) {
-            this.parentNode.removeChild(this);
-          }
-        }.bind(overlayLayer), 500);
-      }.bind(this));
-    }
-
-    //remove all helper layers
-    var helperLayer = targetElement.querySelector('.introjs-helperLayer');
-    if (helperLayer) {
-      helperLayer.parentNode.removeChild(helperLayer);
-    }
-
-    var referenceLayer = targetElement.querySelector('.introjs-tooltipReferenceLayer');
-    if (referenceLayer) {
-      referenceLayer.parentNode.removeChild(referenceLayer);
-    }
-
-    //remove disableInteractionLayer
-    var disableInteractionLayer = targetElement.querySelector('.introjs-disableInteraction');
-    if (disableInteractionLayer) {
-      disableInteractionLayer.parentNode.removeChild(disableInteractionLayer);
-    }
-
-    //remove intro floating element
-    var floatingElement = document.querySelector('.introjsFloatingElement');
-    if (floatingElement) {
-      floatingElement.parentNode.removeChild(floatingElement);
-    }
-
-    _removeShowElement();
-
-    //remove `introjs-fixParent` class from the elements
-    var fixParents = document.querySelectorAll('.introjs-fixParent');
-    _forEach(fixParents, function (parent) {
-      _removeClass(parent, /introjs-fixParent/g);
-    });
-
-    //clean listeners
-    DOMEvent.off(window, 'keydown', _onKeyDown, this, true);
-    DOMEvent.off(window, 'resize', _onResize, this, true);
-
-    //check if any callback is defined
-    if (this._introExitCallback !== undefined) {
-      this._introExitCallback.call(this);
-    }
-
-    //set the step to zero
-    this._currentStep = undefined;
-  }
-
-  /**
-   * Render tooltip box in the page
-   *
-   * @api private
-   * @method _placeTooltip
-   * @param {HTMLElement} targetElement
-   * @param {HTMLElement} tooltipLayer
-   * @param {HTMLElement} arrowLayer
-   * @param {HTMLElement} helperNumberLayer
-   * @param {Boolean} hintMode
-   */
-  function _placeTooltip(targetElement, tooltipLayer, arrowLayer, helperNumberLayer, hintMode) {
-    var tooltipCssClass = '',
-        currentStepObj,
-        tooltipOffset,
-        targetOffset,
-        windowSize,
-        currentTooltipPosition;
-
-    hintMode = hintMode || false;
-
-    //reset the old style
-    tooltipLayer.style.top        = null;
-    tooltipLayer.style.right      = null;
-    tooltipLayer.style.bottom     = null;
-    tooltipLayer.style.left       = null;
-    tooltipLayer.style.marginLeft = null;
-    tooltipLayer.style.marginTop  = null;
-
-    arrowLayer.style.display = 'inherit';
-
-    if (typeof(helperNumberLayer) !== 'undefined' && helperNumberLayer !== null) {
-      helperNumberLayer.style.top  = null;
-      helperNumberLayer.style.left = null;
-    }
-
-    //prevent error when `this._currentStep` is undefined
-    if (!this._introItems[this._currentStep]) return;
-
-    //if we have a custom css class for each step
-    currentStepObj = this._introItems[this._currentStep];
-    if (typeof (currentStepObj.tooltipClass) === 'string') {
-      tooltipCssClass = currentStepObj.tooltipClass;
-    } else {
-      tooltipCssClass = this._options.tooltipClass;
-    }
-
-    tooltipLayer.className = ('introjs-tooltip ' + tooltipCssClass).replace(/^\s+|\s+$/g, '');
-    tooltipLayer.setAttribute('role', 'dialog');
-
-    currentTooltipPosition = this._introItems[this._currentStep].position;
-
-    // Floating is always valid, no point in calculating
-    if (currentTooltipPosition !== "floating") { 
-      currentTooltipPosition = _determineAutoPosition.call(this, targetElement, tooltipLayer, currentTooltipPosition);
-    }
-
-    var tooltipLayerStyleLeft;
-    targetOffset  = _getOffset(targetElement);
-    tooltipOffset = _getOffset(tooltipLayer);
-    windowSize    = _getWinSize();
-
-    _addClass(tooltipLayer, 'introjs-' + currentTooltipPosition);
-
-    switch (currentTooltipPosition) {
-      case 'top-right-aligned':
-        arrowLayer.className      = 'introjs-arrow bottom-right';
-
-        var tooltipLayerStyleRight = 0;
-        _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer);
-        tooltipLayer.style.bottom    = (targetOffset.height +  20) + 'px';
-        break;
-
-      case 'top-middle-aligned':
-        arrowLayer.className      = 'introjs-arrow bottom-middle';
-
-        var tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2;
-
-        // a fix for middle aligned hints
-        if (hintMode) {
-          tooltipLayerStyleLeftRight += 5;
-        }
-
-        if (_checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) {
-          tooltipLayer.style.right = null;
-          _checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer);
-        }
-        tooltipLayer.style.bottom = (targetOffset.height + 20) + 'px';
-        break;
-
-      case 'top-left-aligned':
-      // top-left-aligned is the same as the default top
-      case 'top':
-        arrowLayer.className = 'introjs-arrow bottom';
-
-        tooltipLayerStyleLeft = (hintMode) ? 0 : 15;
-
-        _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer);
-        tooltipLayer.style.bottom = (targetOffset.height +  20) + 'px';
-        break;
-      case 'right':
-        tooltipLayer.style.left = (targetOffset.width + 20) + 'px';
-        if (targetOffset.top + tooltipOffset.height > windowSize.height) {
-          // In this case, right would have fallen below the bottom of the screen.
-          // Modify so that the bottom of the tooltip connects with the target
-          arrowLayer.className = "introjs-arrow left-bottom";
-          tooltipLayer.style.top = "-" + (tooltipOffset.height - targetOffset.height - 20) + "px";
-        } else {
-          arrowLayer.className = 'introjs-arrow left';
-        }
-        break;
-      case 'left':
-        if (!hintMode && this._options.showStepNumbers === true) {
-          tooltipLayer.style.top = '15px';
-        }
-
-        if (targetOffset.top + tooltipOffset.height > windowSize.height) {
-          // In this case, left would have fallen below the bottom of the screen.
-          // Modify so that the bottom of the tooltip connects with the target
-          tooltipLayer.style.top = "-" + (tooltipOffset.height - targetOffset.height - 20) + "px";
-          arrowLayer.className = 'introjs-arrow right-bottom';
-        } else {
-          arrowLayer.className = 'introjs-arrow right';
-        }
-        tooltipLayer.style.right = (targetOffset.width + 20) + 'px';
-
-        break;
-      case 'floating':
-        arrowLayer.style.display = 'none';
-
-        //we have to adjust the top and left of layer manually for intro items without element
-        tooltipLayer.style.left   = '50%';
-        tooltipLayer.style.top    = '50%';
-        tooltipLayer.style.marginLeft = '-' + (tooltipOffset.width / 2)  + 'px';
-        tooltipLayer.style.marginTop  = '-' + (tooltipOffset.height / 2) + 'px';
-
-        if (typeof(helperNumberLayer) !== 'undefined' && helperNumberLayer !== null) {
-          helperNumberLayer.style.left = '-' + ((tooltipOffset.width / 2) + 18) + 'px';
-          helperNumberLayer.style.top  = '-' + ((tooltipOffset.height / 2) + 18) + 'px';
-        }
-
-        break;
-      case 'bottom-right-aligned':
-        arrowLayer.className      = 'introjs-arrow top-right';
-
-        tooltipLayerStyleRight = 0;
-        _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer);
-        tooltipLayer.style.top    = (targetOffset.height +  20) + 'px';
-        break;
-
-      case 'bottom-middle-aligned':
-        arrowLayer.className      = 'introjs-arrow top-middle';
-
-        tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2;
-
-        // a fix for middle aligned hints
-        if (hintMode) {
-          tooltipLayerStyleLeftRight += 5;
-        }
-
-        if (_checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) {
-          tooltipLayer.style.right = null;
-          _checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer);
-        }
-        tooltipLayer.style.top = (targetOffset.height + 20) + 'px';
-        break;
-
-      // case 'bottom-left-aligned':
-      // Bottom-left-aligned is the same as the default bottom
-      // case 'bottom':
-      // Bottom going to follow the default behavior
-      default:
-        arrowLayer.className = 'introjs-arrow top';
-
-        tooltipLayerStyleLeft = 0;
-        _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer);
-        tooltipLayer.style.top    = (targetOffset.height +  20) + 'px';
-    }
-  }
-
-  /**
-   * Set tooltip left so it doesn't go off the right side of the window
-   *
-   * @return boolean true, if tooltipLayerStyleLeft is ok.  false, otherwise.
-   */
-  function _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer) {
-    if (targetOffset.left + tooltipLayerStyleLeft + tooltipOffset.width > windowSize.width) {
-      // off the right side of the window
-      tooltipLayer.style.left = (windowSize.width - tooltipOffset.width - targetOffset.left) + 'px';
-      return false;
-    }
-    tooltipLayer.style.left = tooltipLayerStyleLeft + 'px';
-    return true;
-  }
-
-  /**
-   * Set tooltip right so it doesn't go off the left side of the window
-   *
-   * @return boolean true, if tooltipLayerStyleRight is ok.  false, otherwise.
-   */
-  function _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer) {
-    if (targetOffset.left + targetOffset.width - tooltipLayerStyleRight - tooltipOffset.width < 0) {
-      // off the left side of the window
-      tooltipLayer.style.left = (-targetOffset.left) + 'px';
-      return false;
-    }
-    tooltipLayer.style.right = tooltipLayerStyleRight + 'px';
-    return true;
-  }
-
-  /**
-   * Determines the position of the tooltip based on the position precedence and availability
-   * of screen space.
-   *
-   * @param {Object}    targetElement
-   * @param {Object}    tooltipLayer
-   * @param {String}    desiredTooltipPosition
-   * @return {String}   calculatedPosition
-   */
-  function _determineAutoPosition(targetElement, tooltipLayer, desiredTooltipPosition) {
-
-    // Take a clone of position precedence. These will be the available
-    var possiblePositions = this._options.positionPrecedence.slice();
-
-    var windowSize = _getWinSize();
-    var tooltipHeight = _getOffset(tooltipLayer).height + 10;
-    var tooltipWidth = _getOffset(tooltipLayer).width + 20;
-    var targetElementRect = targetElement.getBoundingClientRect();
-
-    // If we check all the possible areas, and there are no valid places for the tooltip, the element
-    // must take up most of the screen real estate. Show the tooltip floating in the middle of the screen.
-    var calculatedPosition = "floating";
-
-    /*
-    * auto determine position 
-    */
-
-    // Check for space below
-    if (targetElementRect.bottom + tooltipHeight + tooltipHeight > windowSize.height) {
-      _removeEntry(possiblePositions, "bottom");
-    }
-
-    // Check for space above
-    if (targetElementRect.top - tooltipHeight < 0) {
-      _removeEntry(possiblePositions, "top");
-    }
-
-    // Check for space to the right
-    if (targetElementRect.right + tooltipWidth > windowSize.width) {
-      _removeEntry(possiblePositions, "right");
-    }
-
-    // Check for space to the left
-    if (targetElementRect.left - tooltipWidth < 0) {
-      _removeEntry(possiblePositions, "left");
-    }
-
-    // @var {String}  ex: 'right-aligned'
-    var desiredAlignment = (function (pos) {
-      var hyphenIndex = pos.indexOf('-');
-      if (hyphenIndex !== -1) {
-        // has alignment
-        return pos.substr(hyphenIndex);
-      }
-      return '';
-    })(desiredTooltipPosition || '');
-
-    // strip alignment from position
-    if (desiredTooltipPosition) {
-      // ex: "bottom-right-aligned"
-      // should return 'bottom'
-      desiredTooltipPosition = desiredTooltipPosition.split('-')[0];
-    }
-
-    if (possiblePositions.length) {
-      if (desiredTooltipPosition !== "auto" &&
-          possiblePositions.indexOf(desiredTooltipPosition) > -1) {
-        // If the requested position is in the list, choose that
-        calculatedPosition = desiredTooltipPosition;
-      } else {
-        // Pick the first valid position, in order
-        calculatedPosition = possiblePositions[0];
-      }
-    }
-
-    // only top and bottom positions have optional alignments
-    if (['top', 'bottom'].indexOf(calculatedPosition) !== -1) {
-      calculatedPosition += _determineAutoAlignment(targetElementRect.left, tooltipWidth, windowSize, desiredAlignment);
-    }
-
-    return calculatedPosition;
-  }
-
-  /**
-  * auto-determine alignment
-  * @param {Integer}  offsetLeft
-  * @param {Integer}  tooltipWidth
-  * @param {Object}   windowSize
-  * @param {String}   desiredAlignment
-  * @return {String}  calculatedAlignment
-  */
-  function _determineAutoAlignment (offsetLeft, tooltipWidth, windowSize, desiredAlignment) {
-    var halfTooltipWidth = tooltipWidth / 2,
-      winWidth = Math.min(windowSize.width, window.screen.width),
-      possibleAlignments = ['-left-aligned', '-middle-aligned', '-right-aligned'],
-      calculatedAlignment = '';
-    
-    // valid left must be at least a tooltipWidth
-    // away from right side
-    if (winWidth - offsetLeft < tooltipWidth) {
-      _removeEntry(possibleAlignments, '-left-aligned');
-    }
-
-    // valid middle must be at least half 
-    // width away from both sides
-    if (offsetLeft < halfTooltipWidth || 
-      winWidth - offsetLeft < halfTooltipWidth) {
-      _removeEntry(possibleAlignments, '-middle-aligned');
-    }
-
-    // valid right must be at least a tooltipWidth
-    // width away from left side
-    if (offsetLeft < tooltipWidth) {
-      _removeEntry(possibleAlignments, '-right-aligned');
-    }
-
-    if (possibleAlignments.length) {
-      if (possibleAlignments.indexOf(desiredAlignment) !== -1) {
-        // the desired alignment is valid
-        calculatedAlignment = desiredAlignment;
-      } else {
-        // pick the first valid position, in order
-        calculatedAlignment = possibleAlignments[0];
-      }
-    } else {
-      // if screen width is too small 
-      // for ANY alignment, middle is 
-      // probably the best for visibility
-      calculatedAlignment = '-middle-aligned';
-    }
-
-    return calculatedAlignment;
-  }
-
-  /**
-   * Remove an entry from a string array if it's there, does nothing if it isn't there.
-   *
-   * @param {Array} stringArray
-   * @param {String} stringToRemove
-   */
-  function _removeEntry(stringArray, stringToRemove) {
-    if (stringArray.indexOf(stringToRemove) > -1) {
-      stringArray.splice(stringArray.indexOf(stringToRemove), 1);
-    }
-  }
-
-  /**
-   * Update the position of the helper layer on the screen
-   *
-   * @api private
-   * @method _setHelperLayerPosition
-   * @param {Object} helperLayer
-   */
-  function _setHelperLayerPosition(helperLayer) {
-    if (helperLayer) {
-      //prevent error when `this._currentStep` in undefined
-      if (!this._introItems[this._currentStep]) return;
-
-      var currentElement  = this._introItems[this._currentStep],
-          elementPosition = _getOffset(currentElement.element),
-          widthHeightPadding = this._options.helperElementPadding;
-
-      // If the target element is fixed, the tooltip should be fixed as well.
-      // Otherwise, remove a fixed class that may be left over from the previous
-      // step.
-      if (_isFixed(currentElement.element)) {
-        _addClass(helperLayer, 'introjs-fixedTooltip');
-      } else {
-        _removeClass(helperLayer, 'introjs-fixedTooltip');
-      }
-
-      if (currentElement.position === 'floating') {
-        widthHeightPadding = 0;
-      }
-
-      //set new position to helper layer
-      helperLayer.style.cssText = 'width: ' + (elementPosition.width  + widthHeightPadding)  + 'px; ' +
-                                        'height:' + (elementPosition.height + widthHeightPadding)  + 'px; ' +
-                                        'top:'    + (elementPosition.top    - widthHeightPadding / 2)   + 'px;' +
-                                        'left: '  + (elementPosition.left   - widthHeightPadding / 2)   + 'px;';
-
-    }
-  }
-
-  /**
-   * Add disableinteraction layer and adjust the size and position of the layer
-   *
-   * @api private
-   * @method _disableInteraction
-   */
-  function _disableInteraction() {
-    var disableInteractionLayer = document.querySelector('.introjs-disableInteraction');
-
-    if (disableInteractionLayer === null) {
-      disableInteractionLayer = document.createElement('div');
-      disableInteractionLayer.className = 'introjs-disableInteraction';
-      this._targetElement.appendChild(disableInteractionLayer);
-    }
-
-    _setHelperLayerPosition.call(this, disableInteractionLayer);
-  }
-
-  /**
-   * Setting anchors to behave like buttons
-   *
-   * @api private
-   * @method _setAnchorAsButton
-   */
-  function _setAnchorAsButton(anchor){
-    anchor.setAttribute('role', 'button');
-    anchor.tabIndex = 0;
-  }
-
-  /**
-   * Show an element on the page
-   *
-   * @api private
-   * @method _showElement
-   * @param {Object} targetElement
-   */
-  function _showElement(targetElement) {
-    if (typeof (this._introChangeCallback) !== 'undefined') {
-      this._introChangeCallback.call(this, targetElement.element);
-    }
-
-    var self = this,
-        oldHelperLayer = document.querySelector('.introjs-helperLayer'),
-        oldReferenceLayer = document.querySelector('.introjs-tooltipReferenceLayer'),
-        highlightClass = 'introjs-helperLayer',
-        nextTooltipButton,
-        prevTooltipButton,
-        skipTooltipButton,
-        scrollParent;
-
-    //check for a current step highlight class
-    if (typeof (targetElement.highlightClass) === 'string') {
-      highlightClass += (' ' + targetElement.highlightClass);
-    }
-    //check for options highlight class
-    if (typeof (this._options.highlightClass) === 'string') {
-      highlightClass += (' ' + this._options.highlightClass);
-    }
-
-    if (oldHelperLayer !== null) {
-      var oldHelperNumberLayer = oldReferenceLayer.querySelector('.introjs-helperNumberLayer'),
-          oldtooltipLayer      = oldReferenceLayer.querySelector('.introjs-tooltiptext'),
-          oldArrowLayer        = oldReferenceLayer.querySelector('.introjs-arrow'),
-          oldtooltipContainer  = oldReferenceLayer.querySelector('.introjs-tooltip');
-          
-      skipTooltipButton    = oldReferenceLayer.querySelector('.introjs-skipbutton');
-      prevTooltipButton    = oldReferenceLayer.querySelector('.introjs-prevbutton');
-      nextTooltipButton    = oldReferenceLayer.querySelector('.introjs-nextbutton');
-
-      //update or reset the helper highlight class
-      oldHelperLayer.className = highlightClass;
-      //hide the tooltip
-      oldtooltipContainer.style.opacity = 0;
-      oldtooltipContainer.style.display = "none";
-
-      if (oldHelperNumberLayer !== null) {
-        var lastIntroItem = this._introItems[(targetElement.step - 2 >= 0 ? targetElement.step - 2 : 0)];
-
-        if (lastIntroItem !== null && (this._direction === 'forward' && lastIntroItem.position === 'floating') || (this._direction === 'backward' && targetElement.position === 'floating')) {
-          oldHelperNumberLayer.style.opacity = 0;
-        }
-      }
-
-      // scroll to element
-      scrollParent = _getScrollParent( targetElement.element );
-
-      if (scrollParent !== document.body) {
-        // target is within a scrollable element
-        _scrollParentToElement(scrollParent, targetElement.element);
-      }
-
-      // set new position to helper layer
-      _setHelperLayerPosition.call(self, oldHelperLayer);
-      _setHelperLayerPosition.call(self, oldReferenceLayer);
-
-      //remove `introjs-fixParent` class from the elements
-      var fixParents = document.querySelectorAll('.introjs-fixParent');
-      _forEach(fixParents, function (parent) {
-        _removeClass(parent, /introjs-fixParent/g);
-      });
-      
-      //remove old classes if the element still exist
-      _removeShowElement();
-
-      //we should wait until the CSS3 transition is competed (it's 0.3 sec) to prevent incorrect `height` and `width` calculation
-      if (self._lastShowElementTimer) {
-        window.clearTimeout(self._lastShowElementTimer);
-      }
-
-      self._lastShowElementTimer = window.setTimeout(function() {
-        //set current step to the label
-        if (oldHelperNumberLayer !== null) {
-          oldHelperNumberLayer.innerHTML = targetElement.step;
-        }
-        //set current tooltip text
-        oldtooltipLayer.innerHTML = targetElement.intro;
-        //set the tooltip position
-        oldtooltipContainer.style.display = "block";
-        _placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer);
-
-        //change active bullet
-        if (self._options.showBullets) {
-            oldReferenceLayer.querySelector('.introjs-bullets li > a.active').className = '';
-            oldReferenceLayer.querySelector('.introjs-bullets li > a[data-stepnumber="' + targetElement.step + '"]').className = 'active';
-        }
-        oldReferenceLayer.querySelector('.introjs-progress .introjs-progressbar').style.cssText = 'width:' + _getProgress.call(self) + '%;';
-        oldReferenceLayer.querySelector('.introjs-progress .introjs-progressbar').setAttribute('aria-valuenow', _getProgress.call(self));
-
-        //show the tooltip
-        oldtooltipContainer.style.opacity = 1;
-        if (oldHelperNumberLayer) oldHelperNumberLayer.style.opacity = 1;
-
-        //reset button focus
-        if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null && /introjs-donebutton/gi.test(skipTooltipButton.className)) {
-          // skip button is now "done" button
-          skipTooltipButton.focus();
-        } else if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
-          //still in the tour, focus on next
-          nextTooltipButton.focus();
-        }
-
-        // change the scroll of the window, if needed
-        _scrollTo.call(self, targetElement.scrollTo, targetElement, oldtooltipLayer);
-      }, 350);
-
-      // end of old element if-else condition
-    } else {
-      var helperLayer       = document.createElement('div'),
-          referenceLayer    = document.createElement('div'),
-          arrowLayer        = document.createElement('div'),
-          tooltipLayer      = document.createElement('div'),
-          tooltipTextLayer  = document.createElement('div'),
-          bulletsLayer      = document.createElement('div'),
-          progressLayer     = document.createElement('div'),
-          buttonsLayer      = document.createElement('div');
-
-      helperLayer.className = highlightClass;
-      referenceLayer.className = 'introjs-tooltipReferenceLayer';
-
-      // scroll to element
-      scrollParent = _getScrollParent( targetElement.element );
-
-      if (scrollParent !== document.body) {
-        // target is within a scrollable element
-        _scrollParentToElement(scrollParent, targetElement.element);
-      }
-
-      //set new position to helper layer
-      _setHelperLayerPosition.call(self, helperLayer);
-      _setHelperLayerPosition.call(self, referenceLayer);
-
-      //add helper layer to target element
-      this._targetElement.appendChild(helperLayer);
-      this._targetElement.appendChild(referenceLayer);
-
-      arrowLayer.className = 'introjs-arrow';
-
-      tooltipTextLayer.className = 'introjs-tooltiptext';
-      tooltipTextLayer.innerHTML = targetElement.intro;
-
-      bulletsLayer.className = 'introjs-bullets';
-
-      if (this._options.showBullets === false) {
-        bulletsLayer.style.display = 'none';
-      }
-
-      var ulContainer = document.createElement('ul');
-      ulContainer.setAttribute('role', 'tablist');
-
-      var anchorClick = function () {
-          self.goToStep(this.getAttribute('data-stepnumber'));
+    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+      _typeof = function (obj) {
+        return typeof obj;
       };
-
-      _forEach(this._introItems, function (item, i) {
-        var innerLi    = document.createElement('li');
-        var anchorLink = document.createElement('a');
-        
-        innerLi.setAttribute('role', 'presentation');
-        anchorLink.setAttribute('role', 'tab');
-
-        anchorLink.onclick = anchorClick;
-
-        if (i === (targetElement.step-1)) {
-          anchorLink.className = 'active';
-        } 
-
-        _setAnchorAsButton(anchorLink);
-        anchorLink.innerHTML = "&nbsp;";
-        anchorLink.setAttribute('data-stepnumber', item.step);
-
-        innerLi.appendChild(anchorLink);
-        ulContainer.appendChild(innerLi);
-      });
-
-      bulletsLayer.appendChild(ulContainer);
-
-      progressLayer.className = 'introjs-progress';
-
-      if (this._options.showProgress === false) {
-        progressLayer.style.display = 'none';
-      }
-      var progressBar = document.createElement('div');
-      progressBar.className = 'introjs-progressbar';
-      progressBar.setAttribute('role', 'progress');
-      progressBar.setAttribute('aria-valuemin', 0);
-      progressBar.setAttribute('aria-valuemax', 100);
-      progressBar.setAttribute('aria-valuenow', _getProgress.call(this));
-      progressBar.style.cssText = 'width:' + _getProgress.call(this) + '%;';
-
-      progressLayer.appendChild(progressBar);
-
-      buttonsLayer.className = 'introjs-tooltipbuttons';
-      if (this._options.showButtons === false) {
-        buttonsLayer.style.display = 'none';
-      }
-
-      tooltipLayer.className = 'introjs-tooltip';
-      tooltipLayer.appendChild(tooltipTextLayer);
-      tooltipLayer.appendChild(bulletsLayer);
-      tooltipLayer.appendChild(progressLayer);
-
-      //add helper layer number
-      var helperNumberLayer = document.createElement('span');
-      if (this._options.showStepNumbers === true) {
-        helperNumberLayer.className = 'introjs-helperNumberLayer';
-        helperNumberLayer.innerHTML = targetElement.step;
-        referenceLayer.appendChild(helperNumberLayer);
-      }
-
-      tooltipLayer.appendChild(arrowLayer);
-      referenceLayer.appendChild(tooltipLayer);
-
-      //next button
-      nextTooltipButton = document.createElement('a');
-
-      nextTooltipButton.onclick = function() {
-        if (self._introItems.length - 1 !== self._currentStep) {
-          _nextStep.call(self);
-        }
-      };
-
-      _setAnchorAsButton(nextTooltipButton);
-      nextTooltipButton.innerHTML = this._options.nextLabel;
-
-      //previous button
-      prevTooltipButton = document.createElement('a');
-
-      prevTooltipButton.onclick = function() {
-        if (self._currentStep !== 0) {
-          _previousStep.call(self);
-        }
-      };
-
-      _setAnchorAsButton(prevTooltipButton);
-      prevTooltipButton.innerHTML = this._options.prevLabel;
-
-      //skip button
-      skipTooltipButton = document.createElement('a');
-      skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton ';
-      _setAnchorAsButton(skipTooltipButton);
-      skipTooltipButton.innerHTML = this._options.skipLabel;
-
-      skipTooltipButton.onclick = function() {
-        if (self._introItems.length - 1 === self._currentStep && typeof (self._introCompleteCallback) === 'function') {
-          self._introCompleteCallback.call(self);
-        }
-
-        if (self._introItems.length - 1 !== self._currentStep && typeof (self._introExitCallback) === 'function') {
-          self._introExitCallback.call(self);
-        }
-
-        if (typeof(self._introSkipCallback) === 'function') {
-          self._introSkipCallback.call(self);
-        }
-
-        _exitIntro.call(self, self._targetElement);
-      };
-
-      buttonsLayer.appendChild(skipTooltipButton);
-
-      //in order to prevent displaying next/previous button always
-      if (this._introItems.length > 1) {
-        buttonsLayer.appendChild(prevTooltipButton);
-        buttonsLayer.appendChild(nextTooltipButton);
-      }
-
-      tooltipLayer.appendChild(buttonsLayer);
-
-      //set proper position
-      _placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer, helperNumberLayer);
-
-      // change the scroll of the window, if needed
-      _scrollTo.call(this, targetElement.scrollTo, targetElement, tooltipLayer);
-
-      //end of new element if-else condition
-    }
-
-    // removing previous disable interaction layer
-    var disableInteractionLayer = self._targetElement.querySelector('.introjs-disableInteraction');
-    if (disableInteractionLayer) {
-      disableInteractionLayer.parentNode.removeChild(disableInteractionLayer);
-    }
-
-    //disable interaction
-    if (targetElement.disableInteraction) {
-      _disableInteraction.call(self);
-    }
-
-    // when it's the first step of tour
-    if (this._currentStep === 0 && this._introItems.length > 1) {
-      if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) {
-        skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton';
-      }
-      if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
-        nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton';
-      }
-
-      if (this._options.hidePrev === true) {
-        if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
-          prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton introjs-hidden';
-        }
-        if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
-          _addClass(nextTooltipButton, 'introjs-fullbutton');
-        }
-      } else {
-        if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
-          prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton introjs-disabled';
-        }
-      }
-
-      if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) {
-        skipTooltipButton.innerHTML = this._options.skipLabel;
-      }
-    } else if (this._introItems.length - 1 === this._currentStep || this._introItems.length === 1) {
-      // last step of tour
-      if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) {
-        skipTooltipButton.innerHTML = this._options.doneLabel;
-        // adding donebutton class in addition to skipbutton
-        _addClass(skipTooltipButton, 'introjs-donebutton');
-      }
-      if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
-        prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton';
-      }
-
-      if (this._options.hideNext === true) {
-        if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
-          nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton introjs-hidden';
-        }
-        if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
-          _addClass(prevTooltipButton, 'introjs-fullbutton');
-        }
-      } else {
-        if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
-          nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton introjs-disabled';
-        }
-      }
     } else {
-      // steps between start and end
-      if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) {
-        skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton';
-      }
-      if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
-        prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton';
-      }
-      if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
-        nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton';
-      }
-      if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) {
-        skipTooltipButton.innerHTML = this._options.skipLabel;
-      }
+      _typeof = function (obj) {
+        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+      };
     }
 
-    prevTooltipButton.setAttribute('role', 'button');
-    nextTooltipButton.setAttribute('role', 'button');
-    skipTooltipButton.setAttribute('role', 'button');
-
-    //Set focus on "next" button, so that hitting Enter always moves you onto the next step
-    if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
-      nextTooltipButton.focus();
-    }
-
-    _setShowElement(targetElement);
-
-    if (typeof (this._introAfterChangeCallback) !== 'undefined') {
-      this._introAfterChangeCallback.call(this, targetElement.element);
-    }
+    return _typeof(obj);
   }
 
   /**
-   * To change the scroll of `window` after highlighting an element
+   * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
+   * via: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically
    *
-   * @api private
-   * @method _scrollTo
-   * @param {String} scrollTo
-   * @param {Object} targetElement
-   * @param {Object} tooltipLayer
+   * @param obj1
+   * @param obj2
+   * @returns obj3 a new object based on obj1 and obj2
    */
-  function _scrollTo(scrollTo, targetElement, tooltipLayer) {
-    if (scrollTo === 'off') return;  
-    var rect;
+  function mergeOptions(obj1, obj2) {
+    var obj3 = {};
+    var attrname;
 
-    if (!this._options.scrollToElement) return;
-
-    if (scrollTo === 'tooltip') {
-      rect = tooltipLayer.getBoundingClientRect();
-    } else {
-      rect = targetElement.element.getBoundingClientRect();
+    for (attrname in obj1) {
+      obj3[attrname] = obj1[attrname];
     }
 
-    if (!_elementInViewport(targetElement.element)) {
-      var winHeight = _getWinSize().height;
-      var top = rect.bottom - (rect.bottom - rect.top);
-
-      // TODO (afshinm): do we need scroll padding now?
-      // I have changed the scroll option and now it scrolls the window to
-      // the center of the target element or tooltip.
-
-      if (top < 0 || targetElement.element.clientHeight > winHeight) {
-        window.scrollBy(0, rect.top - ((winHeight / 2) -  (rect.height / 2)) - this._options.scrollPadding); // 30px padding from edge to look nice
-
-      //Scroll down
-      } else {
-        window.scrollBy(0, rect.top - ((winHeight / 2) -  (rect.height / 2)) + this._options.scrollPadding); // 30px padding from edge to look nice
-      }
+    for (attrname in obj2) {
+      obj3[attrname] = obj2[attrname];
     }
+
+    return obj3;
   }
 
   /**
-   * To remove all show element(s)
+   * Mark any object with an incrementing number
+   * used for keeping track of objects
    *
-   * @api private
-   * @method _removeShowElement
+   * @param Object obj   Any object or DOM Element
+   * @param String key
+   * @return Object
    */
-  function _removeShowElement() {
-    var elms = document.querySelectorAll('.introjs-showElement');
-
-    _forEach(elms, function (elm) {
-      _removeClass(elm, /introjs-[a-zA-Z]+/g);
-    });
-  }
-
-  /**
-   * To set the show element
-   * This function set a relative (in most cases) position and changes the z-index
-   *
-   * @api private
-   * @method _setShowElement
-   * @param {Object} targetElement
-   */
-  function _setShowElement(targetElement) {
-    var parentElm;
-    // we need to add this show element class to the parent of SVG elements
-    // because the SVG elements can't have independent z-index
-    if (targetElement.element instanceof SVGElement) {
-      parentElm = targetElement.element.parentNode;
-
-      while (targetElement.element.parentNode !== null) {
-        if (!parentElm.tagName || parentElm.tagName.toLowerCase() === 'body') break;
-
-        if (parentElm.tagName.toLowerCase() === 'svg') {
-          _addClass(parentElm, 'introjs-showElement introjs-relativePosition');
-        }
-
-        parentElm = parentElm.parentNode;
-      }
-    }
-
-    _addClass(targetElement.element, 'introjs-showElement');
-
-    var currentElementPosition = _getPropValue(targetElement.element, 'position');
-    if (currentElementPosition !== 'absolute' &&
-        currentElementPosition !== 'relative' &&
-        currentElementPosition !== 'fixed') {
-      //change to new intro item
-      _addClass(targetElement.element, 'introjs-relativePosition');
-    }
-
-    parentElm = targetElement.element.parentNode;
-    while (parentElm !== null) {
-      if (!parentElm.tagName || parentElm.tagName.toLowerCase() === 'body') break;
-
-      //fix The Stacking Context problem.
-      //More detail: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context
-      var zIndex = _getPropValue(parentElm, 'z-index');
-      var opacity = parseFloat(_getPropValue(parentElm, 'opacity'));
-      var transform = _getPropValue(parentElm, 'transform') || _getPropValue(parentElm, '-webkit-transform') || _getPropValue(parentElm, '-moz-transform') || _getPropValue(parentElm, '-ms-transform') || _getPropValue(parentElm, '-o-transform');
-      if (/[0-9]+/.test(zIndex) || opacity < 1 || (transform !== 'none' && transform !== undefined)) {
-        _addClass(parentElm, 'introjs-fixParent');
-      }
-
-      parentElm = parentElm.parentNode;
-    }
-  }
-
-  /**
-  * Iterates arrays
-  *
-  * @param {Array} arr
-  * @param {Function} forEachFnc
-  * @param {Function} completeFnc
-  * @return {Null}
-  */
-  function _forEach(arr, forEachFnc, completeFnc) {
-    // in case arr is an empty query selector node list
-    if (arr) {
-      for (var i = 0, len = arr.length; i < len; i++) {
-        forEachFnc(arr[i], i);
-      }
-    }
-
-    if (typeof(completeFnc) === 'function') {
-      completeFnc();
-    }
-  }
-
-  /**
-  * Mark any object with an incrementing number
-  * used for keeping track of objects
-  *
-  * @param Object obj   Any object or DOM Element
-  * @param String key
-  * @return Object
-  */
-  var _stamp = (function () {
+  var stamp = function () {
     var keys = {};
-    return function stamp (obj, key) {
-      
-      // get group key
-      key = key || 'introjs-stamp';
-
+    return function stamp(obj) {
+      var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "introjs-stamp";
       // each group increments from 0
-      keys[key] = keys[key] || 0;
+      keys[key] = keys[key] || 0; // stamp only once per object
 
-      // stamp only once per object
       if (obj[key] === undefined) {
         // increment key for each new object
         obj[key] = keys[key]++;
@@ -1533,81 +75,107 @@
 
       return obj[key];
     };
-  })();
+  }();
 
   /**
-  * DOMEvent Handles all DOM events
-  *
-  * methods:
-  *
-  * on - add event handler
-  * off - remove event
-  */
-  var DOMEvent = (function () {
-    function DOMEvent () {
-      var events_key = 'introjs_event';
-      
+   * Iterates arrays
+   *
+   * @param {Array} arr
+   * @param {Function} forEachFnc
+   * @param {Function} [completeFnc]
+   * @return {Null}
+   */
+  function forEach(arr, forEachFnc, completeFnc) {
+    // in case arr is an empty query selector node list
+    if (arr) {
+      for (var i = 0, len = arr.length; i < len; i++) {
+        forEachFnc(arr[i], i);
+      }
+    }
+
+    if (typeof completeFnc === "function") {
+      completeFnc();
+    }
+  }
+
+  /**
+   * DOMEvent Handles all DOM events
+   *
+   * methods:
+   *
+   * on - add event handler
+   * off - remove event
+   */
+
+  var DOMEvent = function () {
+    function DOMEvent() {
+      var events_key = "introjs_event";
       /**
-      * Gets a unique ID for an event listener
-      *
-      * @param Object obj
-      * @param String type        event type
-      * @param Function listener
-      * @param Object context
-      * @return String
-      */
+       * Gets a unique ID for an event listener
+       *
+       * @param obj Object
+       * @param type event type
+       * @param listener Function
+       * @param context Object
+       * @return String
+       */
+
       this._id = function (obj, type, listener, context) {
-        return type + _stamp(listener) + (context ? '_' + _stamp(context) : '');
+        return type + stamp(listener) + (context ? "_".concat(stamp(context)) : "");
       };
-
       /**
-      * Adds event listener
-      *
-      * @param Object obj
-      * @param String type        event type
-      * @param Function listener
-      * @param Object context
-      * @param Boolean useCapture
-      * @return null
-      */
-      this.on = function (obj, type, listener, context, useCapture) {
-        var id = this._id.apply(this, arguments),
-            handler = function (e) {
-              return listener.call(context || obj, e || window.event);
-            };
+       * Adds event listener
+       *
+       * @param obj Object obj
+       * @param type String
+       * @param listener Function
+       * @param context Object
+       * @param useCapture Boolean
+       * @return null
+       */
 
-        if ('addEventListener' in obj) {
+
+      this.on = function (obj, type, listener, context, useCapture) {
+        var id = this._id.apply(this, arguments);
+
+        var handler = function handler(e) {
+          return listener.call(context || obj, e || window.event);
+        };
+
+        if ("addEventListener" in obj) {
           obj.addEventListener(type, handler, useCapture);
-        } else if ('attachEvent' in obj) {
-          obj.attachEvent('on' + type, handler);
+        } else if ("attachEvent" in obj) {
+          obj.attachEvent("on".concat(type), handler);
         }
 
         obj[events_key] = obj[events_key] || {};
         obj[events_key][id] = handler;
       };
-
       /**
-      * Removes event listener
-      *
-      * @param Object obj
-      * @param String type        event type
-      * @param Function listener
-      * @param Object context
-      * @param Boolean useCapture
-      * @return null
-      */
+       * Removes event listener
+       *
+       * @param obj Object
+       * @param type String
+       * @param listener Function
+       * @param context Object
+       * @param useCapture Boolean
+       * @return null
+       */
+
+
       this.off = function (obj, type, listener, context, useCapture) {
-        var id = this._id.apply(this, arguments),
-            handler = obj[events_key] && obj[events_key][id];
+        var id = this._id.apply(this, arguments);
+
+        var handler = obj[events_key] && obj[events_key][id];
 
         if (!handler) {
           return;
         }
 
-        if ('removeEventListener' in obj) {
+        if ("removeEventListener" in obj) {
           obj.removeEventListener(type, handler, useCapture);
-        } else if ('detachEvent' in obj) {
-          obj.detachEvent('on' + type, handler);
+        } else if ("detachEvent" in obj) {
+          obj.detachEvent("on".concat(type), handler);
         }
 
         obj[events_key][id] = null;
@@ -1615,8 +183,1400 @@
     }
 
     return new DOMEvent();
+  }();
+
+  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+  function createCommonjsModule(fn, module) {
+  	return module = { exports: {} }, fn(module, module.exports), module.exports;
+  }
+
+  var check = function (it) {
+    return it && it.Math == Math && it;
+  };
+
+  // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
+  var global_1 =
+    // eslint-disable-next-line es/no-global-this -- safe
+    check(typeof globalThis == 'object' && globalThis) ||
+    check(typeof window == 'object' && window) ||
+    // eslint-disable-next-line no-restricted-globals -- safe
+    check(typeof self == 'object' && self) ||
+    check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
+    // eslint-disable-next-line no-new-func -- fallback
+    (function () { return this; })() || Function('return this')();
+
+  var fails = function (exec) {
+    try {
+      return !!exec();
+    } catch (error) {
+      return true;
+    }
+  };
+
+  // Detect IE8's incomplete defineProperty implementation
+  var descriptors = !fails(function () {
+    // eslint-disable-next-line es/no-object-defineproperty -- required for testing
+    return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
+  });
+
+  var $propertyIsEnumerable = {}.propertyIsEnumerable;
+  // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+  var getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
+
+  // Nashorn ~ JDK8 bug
+  var NASHORN_BUG = getOwnPropertyDescriptor$1 && !$propertyIsEnumerable.call({ 1: 2 }, 1);
+
+  // `Object.prototype.propertyIsEnumerable` method implementation
+  // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
+  var f$4 = NASHORN_BUG ? function propertyIsEnumerable(V) {
+    var descriptor = getOwnPropertyDescriptor$1(this, V);
+    return !!descriptor && descriptor.enumerable;
+  } : $propertyIsEnumerable;
+
+  var objectPropertyIsEnumerable = {
+  	f: f$4
+  };
+
+  var createPropertyDescriptor = function (bitmap, value) {
+    return {
+      enumerable: !(bitmap & 1),
+      configurable: !(bitmap & 2),
+      writable: !(bitmap & 4),
+      value: value
+    };
+  };
+
+  var toString = {}.toString;
+
+  var classofRaw = function (it) {
+    return toString.call(it).slice(8, -1);
+  };
+
+  var split = ''.split;
+
+  // fallback for non-array-like ES3 and non-enumerable old V8 strings
+  var indexedObject = fails(function () {
+    // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
+    // eslint-disable-next-line no-prototype-builtins -- safe
+    return !Object('z').propertyIsEnumerable(0);
+  }) ? function (it) {
+    return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
+  } : Object;
+
+  // `RequireObjectCoercible` abstract operation
+  // https://tc39.es/ecma262/#sec-requireobjectcoercible
+  var requireObjectCoercible = function (it) {
+    if (it == undefined) throw TypeError("Can't call method on " + it);
+    return it;
+  };
+
+  // toObject with fallback for non-array-like ES3 strings
+
+
+
+  var toIndexedObject = function (it) {
+    return indexedObject(requireObjectCoercible(it));
+  };
+
+  var isObject = function (it) {
+    return typeof it === 'object' ? it !== null : typeof it === 'function';
+  };
+
+  var aFunction$1 = function (variable) {
+    return typeof variable == 'function' ? variable : undefined;
+  };
+
+  var getBuiltIn = function (namespace, method) {
+    return arguments.length < 2 ? aFunction$1(global_1[namespace]) : global_1[namespace] && global_1[namespace][method];
+  };
+
+  var engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';
+
+  var process = global_1.process;
+  var Deno = global_1.Deno;
+  var versions = process && process.versions || Deno && Deno.version;
+  var v8 = versions && versions.v8;
+  var match, version$1;
+
+  if (v8) {
+    match = v8.split('.');
+    version$1 = match[0] < 4 ? 1 : match[0] + match[1];
+  } else if (engineUserAgent) {
+    match = engineUserAgent.match(/Edge\/(\d+)/);
+    if (!match || match[1] >= 74) {
+      match = engineUserAgent.match(/Chrome\/(\d+)/);
+      if (match) version$1 = match[1];
+    }
+  }
+
+  var engineV8Version = version$1 && +version$1;
+
+  /* eslint-disable es/no-symbol -- required for testing */
+
+
+
+  // eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
+  var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
+    var symbol = Symbol();
+    // Chrome 38 Symbol has incorrect toString conversion
+    // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
+    return !String(symbol) || !(Object(symbol) instanceof Symbol) ||
+      // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
+      !Symbol.sham && engineV8Version && engineV8Version < 41;
+  });
+
+  /* eslint-disable es/no-symbol -- required for testing */
+
+
+  var useSymbolAsUid = nativeSymbol
+    && !Symbol.sham
+    && typeof Symbol.iterator == 'symbol';
+
+  var isSymbol = useSymbolAsUid ? function (it) {
+    return typeof it == 'symbol';
+  } : function (it) {
+    var $Symbol = getBuiltIn('Symbol');
+    return typeof $Symbol == 'function' && Object(it) instanceof $Symbol;
+  };
+
+  // `OrdinaryToPrimitive` abstract operation
+  // https://tc39.es/ecma262/#sec-ordinarytoprimitive
+  var ordinaryToPrimitive = function (input, pref) {
+    var fn, val;
+    if (pref === 'string' && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
+    if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
+    if (pref !== 'string' && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
+    throw TypeError("Can't convert object to primitive value");
+  };
+
+  var setGlobal = function (key, value) {
+    try {
+      // eslint-disable-next-line es/no-object-defineproperty -- safe
+      Object.defineProperty(global_1, key, { value: value, configurable: true, writable: true });
+    } catch (error) {
+      global_1[key] = value;
+    } return value;
+  };
+
+  var SHARED = '__core-js_shared__';
+  var store$1 = global_1[SHARED] || setGlobal(SHARED, {});
+
+  var sharedStore = store$1;
+
+  var shared = createCommonjsModule(function (module) {
+  (module.exports = function (key, value) {
+    return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
+  })('versions', []).push({
+    version: '3.16.1',
+    mode: 'global',
+    copyright: '© 2021 Denis Pushkarev (zloirock.ru)'
+  });
+  });
+
+  // `ToObject` abstract operation
+  // https://tc39.es/ecma262/#sec-toobject
+  var toObject = function (argument) {
+    return Object(requireObjectCoercible(argument));
+  };
+
+  var hasOwnProperty = {}.hasOwnProperty;
+
+  var has$1 = Object.hasOwn || function hasOwn(it, key) {
+    return hasOwnProperty.call(toObject(it), key);
+  };
+
+  var id = 0;
+  var postfix = Math.random();
+
+  var uid = function (key) {
+    return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
+  };
+
+  var WellKnownSymbolsStore = shared('wks');
+  var Symbol$1 = global_1.Symbol;
+  var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;
+
+  var wellKnownSymbol = function (name) {
+    if (!has$1(WellKnownSymbolsStore, name) || !(nativeSymbol || typeof WellKnownSymbolsStore[name] == 'string')) {
+      if (nativeSymbol && has$1(Symbol$1, name)) {
+        WellKnownSymbolsStore[name] = Symbol$1[name];
+      } else {
+        WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name);
+      }
+    } return WellKnownSymbolsStore[name];
+  };
+
+  var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
+
+  // `ToPrimitive` abstract operation
+  // https://tc39.es/ecma262/#sec-toprimitive
+  var toPrimitive = function (input, pref) {
+    if (!isObject(input) || isSymbol(input)) return input;
+    var exoticToPrim = input[TO_PRIMITIVE];
+    var result;
+    if (exoticToPrim !== undefined) {
+      if (pref === undefined) pref = 'default';
+      result = exoticToPrim.call(input, pref);
+      if (!isObject(result) || isSymbol(result)) return result;
+      throw TypeError("Can't convert object to primitive value");
+    }
+    if (pref === undefined) pref = 'number';
+    return ordinaryToPrimitive(input, pref);
+  };
+
+  // `ToPropertyKey` abstract operation
+  // https://tc39.es/ecma262/#sec-topropertykey
+  var toPropertyKey = function (argument) {
+    var key = toPrimitive(argument, 'string');
+    return isSymbol(key) ? key : String(key);
+  };
+
+  var document$1 = global_1.document;
+  // typeof document.createElement is 'object' in old IE
+  var EXISTS = isObject(document$1) && isObject(document$1.createElement);
+
+  var documentCreateElement = function (it) {
+    return EXISTS ? document$1.createElement(it) : {};
+  };
+
+  // Thank's IE8 for his funny defineProperty
+  var ie8DomDefine = !descriptors && !fails(function () {
+    // eslint-disable-next-line es/no-object-defineproperty -- requied for testing
+    return Object.defineProperty(documentCreateElement('div'), 'a', {
+      get: function () { return 7; }
+    }).a != 7;
+  });
+
+  // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+  var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+
+  // `Object.getOwnPropertyDescriptor` method
+  // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
+  var f$3 = descriptors ? $getOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
+    O = toIndexedObject(O);
+    P = toPropertyKey(P);
+    if (ie8DomDefine) try {
+      return $getOwnPropertyDescriptor(O, P);
+    } catch (error) { /* empty */ }
+    if (has$1(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
+  };
+
+  var objectGetOwnPropertyDescriptor = {
+  	f: f$3
+  };
+
+  var anObject = function (it) {
+    if (!isObject(it)) {
+      throw TypeError(String(it) + ' is not an object');
+    } return it;
+  };
+
+  // eslint-disable-next-line es/no-object-defineproperty -- safe
+  var $defineProperty = Object.defineProperty;
+
+  // `Object.defineProperty` method
+  // https://tc39.es/ecma262/#sec-object.defineproperty
+  var f$2 = descriptors ? $defineProperty : function defineProperty(O, P, Attributes) {
+    anObject(O);
+    P = toPropertyKey(P);
+    anObject(Attributes);
+    if (ie8DomDefine) try {
+      return $defineProperty(O, P, Attributes);
+    } catch (error) { /* empty */ }
+    if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
+    if ('value' in Attributes) O[P] = Attributes.value;
+    return O;
+  };
+
+  var objectDefineProperty = {
+  	f: f$2
+  };
+
+  var createNonEnumerableProperty = descriptors ? function (object, key, value) {
+    return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
+  } : function (object, key, value) {
+    object[key] = value;
+    return object;
+  };
+
+  var functionToString = Function.toString;
+
+  // this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
+  if (typeof sharedStore.inspectSource != 'function') {
+    sharedStore.inspectSource = function (it) {
+      return functionToString.call(it);
+    };
+  }
+
+  var inspectSource = sharedStore.inspectSource;
+
+  var WeakMap$1 = global_1.WeakMap;
+
+  var nativeWeakMap = typeof WeakMap$1 === 'function' && /native code/.test(inspectSource(WeakMap$1));
+
+  var keys = shared('keys');
+
+  var sharedKey = function (key) {
+    return keys[key] || (keys[key] = uid(key));
+  };
+
+  var hiddenKeys$1 = {};
+
+  var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
+  var WeakMap = global_1.WeakMap;
+  var set, get, has;
+
+  var enforce = function (it) {
+    return has(it) ? get(it) : set(it, {});
+  };
+
+  var getterFor = function (TYPE) {
+    return function (it) {
+      var state;
+      if (!isObject(it) || (state = get(it)).type !== TYPE) {
+        throw TypeError('Incompatible receiver, ' + TYPE + ' required');
+      } return state;
+    };
+  };
+
+  if (nativeWeakMap || sharedStore.state) {
+    var store = sharedStore.state || (sharedStore.state = new WeakMap());
+    var wmget = store.get;
+    var wmhas = store.has;
+    var wmset = store.set;
+    set = function (it, metadata) {
+      if (wmhas.call(store, it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
+      metadata.facade = it;
+      wmset.call(store, it, metadata);
+      return metadata;
+    };
+    get = function (it) {
+      return wmget.call(store, it) || {};
+    };
+    has = function (it) {
+      return wmhas.call(store, it);
+    };
+  } else {
+    var STATE = sharedKey('state');
+    hiddenKeys$1[STATE] = true;
+    set = function (it, metadata) {
+      if (has$1(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
+      metadata.facade = it;
+      createNonEnumerableProperty(it, STATE, metadata);
+      return metadata;
+    };
+    get = function (it) {
+      return has$1(it, STATE) ? it[STATE] : {};
+    };
+    has = function (it) {
+      return has$1(it, STATE);
+    };
+  }
+
+  var internalState = {
+    set: set,
+    get: get,
+    has: has,
+    enforce: enforce,
+    getterFor: getterFor
+  };
+
+  var redefine = createCommonjsModule(function (module) {
+  var getInternalState = internalState.get;
+  var enforceInternalState = internalState.enforce;
+  var TEMPLATE = String(String).split('String');
+
+  (module.exports = function (O, key, value, options) {
+    var unsafe = options ? !!options.unsafe : false;
+    var simple = options ? !!options.enumerable : false;
+    var noTargetGet = options ? !!options.noTargetGet : false;
+    var state;
+    if (typeof value == 'function') {
+      if (typeof key == 'string' && !has$1(value, 'name')) {
+        createNonEnumerableProperty(value, 'name', key);
+      }
+      state = enforceInternalState(value);
+      if (!state.source) {
+        state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
+      }
+    }
+    if (O === global_1) {
+      if (simple) O[key] = value;
+      else setGlobal(key, value);
+      return;
+    } else if (!unsafe) {
+      delete O[key];
+    } else if (!noTargetGet && O[key]) {
+      simple = true;
+    }
+    if (simple) O[key] = value;
+    else createNonEnumerableProperty(O, key, value);
+  // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
+  })(Function.prototype, 'toString', function toString() {
+    return typeof this == 'function' && getInternalState(this).source || inspectSource(this);
+  });
+  });
+
+  var ceil = Math.ceil;
+  var floor$2 = Math.floor;
+
+  // `ToInteger` abstract operation
+  // https://tc39.es/ecma262/#sec-tointeger
+  var toInteger = function (argument) {
+    return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor$2 : ceil)(argument);
+  };
+
+  var min$4 = Math.min;
+
+  // `ToLength` abstract operation
+  // https://tc39.es/ecma262/#sec-tolength
+  var toLength = function (argument) {
+    return argument > 0 ? min$4(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
+  };
+
+  var max$3 = Math.max;
+  var min$3 = Math.min;
+
+  // Helper for a popular repeating case of the spec:
+  // Let integer be ? ToInteger(index).
+  // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
+  var toAbsoluteIndex = function (index, length) {
+    var integer = toInteger(index);
+    return integer < 0 ? max$3(integer + length, 0) : min$3(integer, length);
+  };
+
+  // `Array.prototype.{ indexOf, includes }` methods implementation
+  var createMethod$2 = function (IS_INCLUDES) {
+    return function ($this, el, fromIndex) {
+      var O = toIndexedObject($this);
+      var length = toLength(O.length);
+      var index = toAbsoluteIndex(fromIndex, length);
+      var value;
+      // Array#includes uses SameValueZero equality algorithm
+      // eslint-disable-next-line no-self-compare -- NaN check
+      if (IS_INCLUDES && el != el) while (length > index) {
+        value = O[index++];
+        // eslint-disable-next-line no-self-compare -- NaN check
+        if (value != value) return true;
+      // Array#indexOf ignores holes, Array#includes - not
+      } else for (;length > index; index++) {
+        if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
+      } return !IS_INCLUDES && -1;
+    };
+  };
+
+  var arrayIncludes = {
+    // `Array.prototype.includes` method
+    // https://tc39.es/ecma262/#sec-array.prototype.includes
+    includes: createMethod$2(true),
+    // `Array.prototype.indexOf` method
+    // https://tc39.es/ecma262/#sec-array.prototype.indexof
+    indexOf: createMethod$2(false)
+  };
+
+  var indexOf = arrayIncludes.indexOf;
+
+
+  var objectKeysInternal = function (object, names) {
+    var O = toIndexedObject(object);
+    var i = 0;
+    var result = [];
+    var key;
+    for (key in O) !has$1(hiddenKeys$1, key) && has$1(O, key) && result.push(key);
+    // Don't enum bug & hidden keys
+    while (names.length > i) if (has$1(O, key = names[i++])) {
+      ~indexOf(result, key) || result.push(key);
+    }
+    return result;
+  };
+
+  // IE8- don't enum bug keys
+  var enumBugKeys = [
+    'constructor',
+    'hasOwnProperty',
+    'isPrototypeOf',
+    'propertyIsEnumerable',
+    'toLocaleString',
+    'toString',
+    'valueOf'
+  ];
+
+  var hiddenKeys = enumBugKeys.concat('length', 'prototype');
+
+  // `Object.getOwnPropertyNames` method
+  // https://tc39.es/ecma262/#sec-object.getownpropertynames
+  // eslint-disable-next-line es/no-object-getownpropertynames -- safe
+  var f$1 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
+    return objectKeysInternal(O, hiddenKeys);
+  };
+
+  var objectGetOwnPropertyNames = {
+  	f: f$1
+  };
+
+  // eslint-disable-next-line es/no-object-getownpropertysymbols -- safe
+  var f = Object.getOwnPropertySymbols;
+
+  var objectGetOwnPropertySymbols = {
+  	f: f
+  };
+
+  // all object keys, includes non-enumerable and symbols
+  var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
+    var keys = objectGetOwnPropertyNames.f(anObject(it));
+    var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
+    return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
+  };
+
+  var copyConstructorProperties = function (target, source) {
+    var keys = ownKeys(source);
+    var defineProperty = objectDefineProperty.f;
+    var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
+    for (var i = 0; i < keys.length; i++) {
+      var key = keys[i];
+      if (!has$1(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
+    }
+  };
+
+  var replacement = /#|\.prototype\./;
+
+  var isForced = function (feature, detection) {
+    var value = data[normalize(feature)];
+    return value == POLYFILL ? true
+      : value == NATIVE ? false
+      : typeof detection == 'function' ? fails(detection)
+      : !!detection;
+  };
+
+  var normalize = isForced.normalize = function (string) {
+    return String(string).replace(replacement, '.').toLowerCase();
+  };
+
+  var data = isForced.data = {};
+  var NATIVE = isForced.NATIVE = 'N';
+  var POLYFILL = isForced.POLYFILL = 'P';
+
+  var isForced_1 = isForced;
+
+  var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
+
+
+
+
+
+
+  /*
+    options.target      - name of the target object
+    options.global      - target is the global object
+    options.stat        - export as static methods of target
+    options.proto       - export as prototype methods of target
+    options.real        - real prototype method for the `pure` version
+    options.forced      - export even if the native feature is available
+    options.bind        - bind methods to the target, required for the `pure` version
+    options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
+    options.unsafe      - use the simple assignment of property instead of delete + defineProperty
+    options.sham        - add a flag to not completely full polyfills
+    options.enumerable  - export as enumerable property
+    options.noTargetGet - prevent calling a getter on target
+  */
+  var _export = function (options, source) {
+    var TARGET = options.target;
+    var GLOBAL = options.global;
+    var STATIC = options.stat;
+    var FORCED, target, key, targetProperty, sourceProperty, descriptor;
+    if (GLOBAL) {
+      target = global_1;
+    } else if (STATIC) {
+      target = global_1[TARGET] || setGlobal(TARGET, {});
+    } else {
+      target = (global_1[TARGET] || {}).prototype;
+    }
+    if (target) for (key in source) {
+      sourceProperty = source[key];
+      if (options.noTargetGet) {
+        descriptor = getOwnPropertyDescriptor(target, key);
+        targetProperty = descriptor && descriptor.value;
+      } else targetProperty = target[key];
+      FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
+      // contained in target
+      if (!FORCED && targetProperty !== undefined) {
+        if (typeof sourceProperty === typeof targetProperty) continue;
+        copyConstructorProperties(sourceProperty, targetProperty);
+      }
+      // add a flag to not completely full polyfills
+      if (options.sham || (targetProperty && targetProperty.sham)) {
+        createNonEnumerableProperty(sourceProperty, 'sham', true);
+      }
+      // extend global
+      redefine(target, key, sourceProperty, options);
+    }
+  };
+
+  var toString_1 = function (argument) {
+    if (isSymbol(argument)) throw TypeError('Cannot convert a Symbol value to a string');
+    return String(argument);
+  };
+
+  // `RegExp.prototype.flags` getter implementation
+  // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
+  var regexpFlags = function () {
+    var that = anObject(this);
+    var result = '';
+    if (that.global) result += 'g';
+    if (that.ignoreCase) result += 'i';
+    if (that.multiline) result += 'm';
+    if (that.dotAll) result += 's';
+    if (that.unicode) result += 'u';
+    if (that.sticky) result += 'y';
+    return result;
+  };
+
+  // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError,
+  var RE = function (s, f) {
+    return RegExp(s, f);
+  };
+
+  var UNSUPPORTED_Y$2 = fails(function () {
+    var re = RE('a', 'y');
+    re.lastIndex = 2;
+    return re.exec('abcd') != null;
+  });
+
+  var BROKEN_CARET = fails(function () {
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
+    var re = RE('^r', 'gy');
+    re.lastIndex = 2;
+    return re.exec('str') != null;
+  });
+
+  var regexpStickyHelpers = {
+  	UNSUPPORTED_Y: UNSUPPORTED_Y$2,
+  	BROKEN_CARET: BROKEN_CARET
+  };
+
+  // `Object.keys` method
+  // https://tc39.es/ecma262/#sec-object.keys
+  // eslint-disable-next-line es/no-object-keys -- safe
+  var objectKeys = Object.keys || function keys(O) {
+    return objectKeysInternal(O, enumBugKeys);
+  };
+
+  // `Object.defineProperties` method
+  // https://tc39.es/ecma262/#sec-object.defineproperties
+  // eslint-disable-next-line es/no-object-defineproperties -- safe
+  var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
+    anObject(O);
+    var keys = objectKeys(Properties);
+    var length = keys.length;
+    var index = 0;
+    var key;
+    while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);
+    return O;
+  };
+
+  var html = getBuiltIn('document', 'documentElement');
+
+  /* global ActiveXObject -- old IE, WSH */
+
+
+
+
+
+
+
+
+  var GT = '>';
+  var LT = '<';
+  var PROTOTYPE = 'prototype';
+  var SCRIPT = 'script';
+  var IE_PROTO = sharedKey('IE_PROTO');
+
+  var EmptyConstructor = function () { /* empty */ };
+
+  var scriptTag = function (content) {
+    return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
+  };
+
+  // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
+  var NullProtoObjectViaActiveX = function (activeXDocument) {
+    activeXDocument.write(scriptTag(''));
+    activeXDocument.close();
+    var temp = activeXDocument.parentWindow.Object;
+    activeXDocument = null; // avoid memory leak
+    return temp;
+  };
+
+  // Create object with fake `null` prototype: use iframe Object with cleared prototype
+  var NullProtoObjectViaIFrame = function () {
+    // Thrash, waste and sodomy: IE GC bug
+    var iframe = documentCreateElement('iframe');
+    var JS = 'java' + SCRIPT + ':';
+    var iframeDocument;
+    if (iframe.style) {
+      iframe.style.display = 'none';
+      html.appendChild(iframe);
+      // https://github.com/zloirock/core-js/issues/475
+      iframe.src = String(JS);
+      iframeDocument = iframe.contentWindow.document;
+      iframeDocument.open();
+      iframeDocument.write(scriptTag('document.F=Object'));
+      iframeDocument.close();
+      return iframeDocument.F;
+    }
+  };
+
+  // Check for document.domain and active x support
+  // No need to use active x approach when document.domain is not set
+  // see https://github.com/es-shims/es5-shim/issues/150
+  // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
+  // avoid IE GC bug
+  var activeXDocument;
+  var NullProtoObject = function () {
+    try {
+      activeXDocument = new ActiveXObject('htmlfile');
+    } catch (error) { /* ignore */ }
+    NullProtoObject = document.domain && activeXDocument ?
+      NullProtoObjectViaActiveX(activeXDocument) : // old IE
+      NullProtoObjectViaIFrame() ||
+      NullProtoObjectViaActiveX(activeXDocument); // WSH
+    var length = enumBugKeys.length;
+    while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]];
+    return NullProtoObject();
+  };
+
+  hiddenKeys$1[IE_PROTO] = true;
+
+  // `Object.create` method
+  // https://tc39.es/ecma262/#sec-object.create
+  var objectCreate = Object.create || function create(O, Properties) {
+    var result;
+    if (O !== null) {
+      EmptyConstructor[PROTOTYPE] = anObject(O);
+      result = new EmptyConstructor();
+      EmptyConstructor[PROTOTYPE] = null;
+      // add "__proto__" for Object.getPrototypeOf polyfill
+      result[IE_PROTO] = O;
+    } else result = NullProtoObject();
+    return Properties === undefined ? result : objectDefineProperties(result, Properties);
+  };
+
+  var regexpUnsupportedDotAll = fails(function () {
+    // babel-minify transpiles RegExp('.', 's') -> /./s and it causes SyntaxError
+    var re = RegExp('.', (typeof '').charAt(0));
+    return !(re.dotAll && re.exec('\n') && re.flags === 's');
+  });
+
+  var regexpUnsupportedNcg = fails(function () {
+    // babel-minify transpiles RegExp('.', 'g') -> /./g and it causes SyntaxError
+    var re = RegExp('(?<a>b)', (typeof '').charAt(5));
+    return re.exec('b').groups.a !== 'b' ||
+      'b'.replace(re, '$<a>c') !== 'bc';
+  });
+
+  /* eslint-disable regexp/no-assertion-capturing-group, regexp/no-empty-group, regexp/no-lazy-ends -- testing */
+  /* eslint-disable regexp/no-useless-quantifier -- testing */
+
+
+
+
+
+  var getInternalState = internalState.get;
+
+
+
+  var nativeExec = RegExp.prototype.exec;
+  var nativeReplace = shared('native-string-replace', String.prototype.replace);
+
+  var patchedExec = nativeExec;
+
+  var UPDATES_LAST_INDEX_WRONG = (function () {
+    var re1 = /a/;
+    var re2 = /b*/g;
+    nativeExec.call(re1, 'a');
+    nativeExec.call(re2, 'a');
+    return re1.lastIndex !== 0 || re2.lastIndex !== 0;
   })();
 
+  var UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y || regexpStickyHelpers.BROKEN_CARET;
+
+  // nonparticipating capturing group, copied from es5-shim's String#split patch.
+  var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
+
+  var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$1 || regexpUnsupportedDotAll || regexpUnsupportedNcg;
+
+  if (PATCH) {
+    // eslint-disable-next-line max-statements -- TODO
+    patchedExec = function exec(string) {
+      var re = this;
+      var state = getInternalState(re);
+      var str = toString_1(string);
+      var raw = state.raw;
+      var result, reCopy, lastIndex, match, i, object, group;
+
+      if (raw) {
+        raw.lastIndex = re.lastIndex;
+        result = patchedExec.call(raw, str);
+        re.lastIndex = raw.lastIndex;
+        return result;
+      }
+
+      var groups = state.groups;
+      var sticky = UNSUPPORTED_Y$1 && re.sticky;
+      var flags = regexpFlags.call(re);
+      var source = re.source;
+      var charsAdded = 0;
+      var strCopy = str;
+
+      if (sticky) {
+        flags = flags.replace('y', '');
+        if (flags.indexOf('g') === -1) {
+          flags += 'g';
+        }
+
+        strCopy = str.slice(re.lastIndex);
+        // Support anchored sticky behavior.
+        if (re.lastIndex > 0 && (!re.multiline || re.multiline && str.charAt(re.lastIndex - 1) !== '\n')) {
+          source = '(?: ' + source + ')';
+          strCopy = ' ' + strCopy;
+          charsAdded++;
+        }
+        // ^(? + rx + ) is needed, in combination with some str slicing, to
+        // simulate the 'y' flag.
+        reCopy = new RegExp('^(?:' + source + ')', flags);
+      }
+
+      if (NPCG_INCLUDED) {
+        reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
+      }
+      if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
+
+      match = nativeExec.call(sticky ? reCopy : re, strCopy);
+
+      if (sticky) {
+        if (match) {
+          match.input = match.input.slice(charsAdded);
+          match[0] = match[0].slice(charsAdded);
+          match.index = re.lastIndex;
+          re.lastIndex += match[0].length;
+        } else re.lastIndex = 0;
+      } else if (UPDATES_LAST_INDEX_WRONG && match) {
+        re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
+      }
+      if (NPCG_INCLUDED && match && match.length > 1) {
+        // Fix browsers whose `exec` methods don't consistently return `undefined`
+        // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
+        nativeReplace.call(match[0], reCopy, function () {
+          for (i = 1; i < arguments.length - 2; i++) {
+            if (arguments[i] === undefined) match[i] = undefined;
+          }
+        });
+      }
+
+      if (match && groups) {
+        match.groups = object = objectCreate(null);
+        for (i = 0; i < groups.length; i++) {
+          group = groups[i];
+          object[group[0]] = match[group[1]];
+        }
+      }
+
+      return match;
+    };
+  }
+
+  var regexpExec = patchedExec;
+
+  // `RegExp.prototype.exec` method
+  // https://tc39.es/ecma262/#sec-regexp.prototype.exec
+  _export({ target: 'RegExp', proto: true, forced: /./.exec !== regexpExec }, {
+    exec: regexpExec
+  });
+
+  // TODO: Remove from `core-js@4` since it's moved to entry points
+
+
+
+
+
+
+
+  var SPECIES$4 = wellKnownSymbol('species');
+  var RegExpPrototype$1 = RegExp.prototype;
+
+  var fixRegexpWellKnownSymbolLogic = function (KEY, exec, FORCED, SHAM) {
+    var SYMBOL = wellKnownSymbol(KEY);
+
+    var DELEGATES_TO_SYMBOL = !fails(function () {
+      // String methods call symbol-named RegEp methods
+      var O = {};
+      O[SYMBOL] = function () { return 7; };
+      return ''[KEY](O) != 7;
+    });
+
+    var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
+      // Symbol-named RegExp methods call .exec
+      var execCalled = false;
+      var re = /a/;
+
+      if (KEY === 'split') {
+        // We can't use real regex here since it causes deoptimization
+        // and serious performance degradation in V8
+        // https://github.com/zloirock/core-js/issues/306
+        re = {};
+        // RegExp[@@split] doesn't call the regex's exec method, but first creates
+        // a new one. We need to return the patched regex when creating the new one.
+        re.constructor = {};
+        re.constructor[SPECIES$4] = function () { return re; };
+        re.flags = '';
+        re[SYMBOL] = /./[SYMBOL];
+      }
+
+      re.exec = function () { execCalled = true; return null; };
+
+      re[SYMBOL]('');
+      return !execCalled;
+    });
+
+    if (
+      !DELEGATES_TO_SYMBOL ||
+      !DELEGATES_TO_EXEC ||
+      FORCED
+    ) {
+      var nativeRegExpMethod = /./[SYMBOL];
+      var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
+        var $exec = regexp.exec;
+        if ($exec === regexpExec || $exec === RegExpPrototype$1.exec) {
+          if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
+            // The native String method already delegates to @@method (this
+            // polyfilled function), leasing to infinite recursion.
+            // We avoid it by directly calling the native @@method method.
+            return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
+          }
+          return { done: true, value: nativeMethod.call(str, regexp, arg2) };
+        }
+        return { done: false };
+      });
+
+      redefine(String.prototype, KEY, methods[0]);
+      redefine(RegExpPrototype$1, SYMBOL, methods[1]);
+    }
+
+    if (SHAM) createNonEnumerableProperty(RegExpPrototype$1[SYMBOL], 'sham', true);
+  };
+
+  // `String.prototype.codePointAt` methods implementation
+  var createMethod$1 = function (CONVERT_TO_STRING) {
+    return function ($this, pos) {
+      var S = toString_1(requireObjectCoercible($this));
+      var position = toInteger(pos);
+      var size = S.length;
+      var first, second;
+      if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
+      first = S.charCodeAt(position);
+      return first < 0xD800 || first > 0xDBFF || position + 1 === size
+        || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
+          ? CONVERT_TO_STRING ? S.charAt(position) : first
+          : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
+    };
+  };
+
+  var stringMultibyte = {
+    // `String.prototype.codePointAt` method
+    // https://tc39.es/ecma262/#sec-string.prototype.codepointat
+    codeAt: createMethod$1(false),
+    // `String.prototype.at` method
+    // https://github.com/mathiasbynens/String.prototype.at
+    charAt: createMethod$1(true)
+  };
+
+  var charAt = stringMultibyte.charAt;
+
+  // `AdvanceStringIndex` abstract operation
+  // https://tc39.es/ecma262/#sec-advancestringindex
+  var advanceStringIndex = function (S, index, unicode) {
+    return index + (unicode ? charAt(S, index).length : 1);
+  };
+
+  // `RegExpExec` abstract operation
+  // https://tc39.es/ecma262/#sec-regexpexec
+  var regexpExecAbstract = function (R, S) {
+    var exec = R.exec;
+    if (typeof exec === 'function') {
+      var result = exec.call(R, S);
+      if (typeof result !== 'object') {
+        throw TypeError('RegExp exec method returned something other than an Object or null');
+      }
+      return result;
+    }
+
+    if (classofRaw(R) !== 'RegExp') {
+      throw TypeError('RegExp#exec called on incompatible receiver');
+    }
+
+    return regexpExec.call(R, S);
+  };
+
+  // @@match logic
+  fixRegexpWellKnownSymbolLogic('match', function (MATCH, nativeMatch, maybeCallNative) {
+    return [
+      // `String.prototype.match` method
+      // https://tc39.es/ecma262/#sec-string.prototype.match
+      function match(regexp) {
+        var O = requireObjectCoercible(this);
+        var matcher = regexp == undefined ? undefined : regexp[MATCH];
+        return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](toString_1(O));
+      },
+      // `RegExp.prototype[@@match]` method
+      // https://tc39.es/ecma262/#sec-regexp.prototype-@@match
+      function (string) {
+        var rx = anObject(this);
+        var S = toString_1(string);
+        var res = maybeCallNative(nativeMatch, rx, S);
+
+        if (res.done) return res.value;
+
+        if (!rx.global) return regexpExecAbstract(rx, S);
+
+        var fullUnicode = rx.unicode;
+        rx.lastIndex = 0;
+        var A = [];
+        var n = 0;
+        var result;
+        while ((result = regexpExecAbstract(rx, S)) !== null) {
+          var matchStr = toString_1(result[0]);
+          A[n] = matchStr;
+          if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
+          n++;
+        }
+        return n === 0 ? null : A;
+      }
+    ];
+  });
+
+  // `IsArray` abstract operation
+  // https://tc39.es/ecma262/#sec-isarray
+  // eslint-disable-next-line es/no-array-isarray -- safe
+  var isArray = Array.isArray || function isArray(arg) {
+    return classofRaw(arg) == 'Array';
+  };
+
+  var createProperty = function (object, key, value) {
+    var propertyKey = toPropertyKey(key);
+    if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));
+    else object[propertyKey] = value;
+  };
+
+  var SPECIES$3 = wellKnownSymbol('species');
+
+  // a part of `ArraySpeciesCreate` abstract operation
+  // https://tc39.es/ecma262/#sec-arrayspeciescreate
+  var arraySpeciesConstructor = function (originalArray) {
+    var C;
+    if (isArray(originalArray)) {
+      C = originalArray.constructor;
+      // cross-realm fallback
+      if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;
+      else if (isObject(C)) {
+        C = C[SPECIES$3];
+        if (C === null) C = undefined;
+      }
+    } return C === undefined ? Array : C;
+  };
+
+  // `ArraySpeciesCreate` abstract operation
+  // https://tc39.es/ecma262/#sec-arrayspeciescreate
+  var arraySpeciesCreate = function (originalArray, length) {
+    return new (arraySpeciesConstructor(originalArray))(length === 0 ? 0 : length);
+  };
+
+  var SPECIES$2 = wellKnownSymbol('species');
+
+  var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
+    // We can't use this feature detection in V8 since it causes
+    // deoptimization and serious performance degradation
+    // https://github.com/zloirock/core-js/issues/677
+    return engineV8Version >= 51 || !fails(function () {
+      var array = [];
+      var constructor = array.constructor = {};
+      constructor[SPECIES$2] = function () {
+        return { foo: 1 };
+      };
+      return array[METHOD_NAME](Boolean).foo !== 1;
+    });
+  };
+
+  var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
+  var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
+  var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
+
+  // We can't use this feature detection in V8 since it causes
+  // deoptimization and serious performance degradation
+  // https://github.com/zloirock/core-js/issues/679
+  var IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {
+    var array = [];
+    array[IS_CONCAT_SPREADABLE] = false;
+    return array.concat()[0] !== array;
+  });
+
+  var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');
+
+  var isConcatSpreadable = function (O) {
+    if (!isObject(O)) return false;
+    var spreadable = O[IS_CONCAT_SPREADABLE];
+    return spreadable !== undefined ? !!spreadable : isArray(O);
+  };
+
+  var FORCED$1 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;
+
+  // `Array.prototype.concat` method
+  // https://tc39.es/ecma262/#sec-array.prototype.concat
+  // with adding support of @@isConcatSpreadable and @@species
+  _export({ target: 'Array', proto: true, forced: FORCED$1 }, {
+    // eslint-disable-next-line no-unused-vars -- required for `.length`
+    concat: function concat(arg) {
+      var O = toObject(this);
+      var A = arraySpeciesCreate(O, 0);
+      var n = 0;
+      var i, k, length, len, E;
+      for (i = -1, length = arguments.length; i < length; i++) {
+        E = i === -1 ? O : arguments[i];
+        if (isConcatSpreadable(E)) {
+          len = toLength(E.length);
+          if (n + len > MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
+          for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
+        } else {
+          if (n >= MAX_SAFE_INTEGER$1) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
+          createProperty(A, n++, E);
+        }
+      }
+      A.length = n;
+      return A;
+    }
+  });
+
+  var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
+  var test$1 = {};
+
+  test$1[TO_STRING_TAG$1] = 'z';
+
+  var toStringTagSupport = String(test$1) === '[object z]';
+
+  var TO_STRING_TAG = wellKnownSymbol('toStringTag');
+  // ES3 wrong here
+  var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';
+
+  // fallback for IE11 Script Access Denied error
+  var tryGet = function (it, key) {
+    try {
+      return it[key];
+    } catch (error) { /* empty */ }
+  };
+
+  // getting tag from ES6+ `Object.prototype.toString`
+  var classof = toStringTagSupport ? classofRaw : function (it) {
+    var O, tag, result;
+    return it === undefined ? 'Undefined' : it === null ? 'Null'
+      // @@toStringTag case
+      : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG)) == 'string' ? tag
+      // builtinTag case
+      : CORRECT_ARGUMENTS ? classofRaw(O)
+      // ES3 arguments fallback
+      : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
+  };
+
+  // `Object.prototype.toString` method implementation
+  // https://tc39.es/ecma262/#sec-object.prototype.tostring
+  var objectToString = toStringTagSupport ? {}.toString : function toString() {
+    return '[object ' + classof(this) + ']';
+  };
+
+  // `Object.prototype.toString` method
+  // https://tc39.es/ecma262/#sec-object.prototype.tostring
+  if (!toStringTagSupport) {
+    redefine(Object.prototype, 'toString', objectToString, { unsafe: true });
+  }
+
+  var TO_STRING = 'toString';
+  var RegExpPrototype = RegExp.prototype;
+  var nativeToString = RegExpPrototype[TO_STRING];
+
+  var NOT_GENERIC = fails(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; });
+  // FF44- RegExp#toString has a wrong name
+  var INCORRECT_NAME = nativeToString.name != TO_STRING;
+
+  // `RegExp.prototype.toString` method
+  // https://tc39.es/ecma262/#sec-regexp.prototype.tostring
+  if (NOT_GENERIC || INCORRECT_NAME) {
+    redefine(RegExp.prototype, TO_STRING, function toString() {
+      var R = anObject(this);
+      var p = toString_1(R.source);
+      var rf = R.flags;
+      var f = toString_1(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? regexpFlags.call(R) : rf);
+      return '/' + p + '/' + f;
+    }, { unsafe: true });
+  }
+
+  var MATCH$1 = wellKnownSymbol('match');
+
+  // `IsRegExp` abstract operation
+  // https://tc39.es/ecma262/#sec-isregexp
+  var isRegexp = function (it) {
+    var isRegExp;
+    return isObject(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
+  };
+
+  var aFunction = function (it) {
+    if (typeof it != 'function') {
+      throw TypeError(String(it) + ' is not a function');
+    } return it;
+  };
+
+  var SPECIES$1 = wellKnownSymbol('species');
+
+  // `SpeciesConstructor` abstract operation
+  // https://tc39.es/ecma262/#sec-speciesconstructor
+  var speciesConstructor = function (O, defaultConstructor) {
+    var C = anObject(O).constructor;
+    var S;
+    return C === undefined || (S = anObject(C)[SPECIES$1]) == undefined ? defaultConstructor : aFunction(S);
+  };
+
+  var UNSUPPORTED_Y = regexpStickyHelpers.UNSUPPORTED_Y;
+  var arrayPush = [].push;
+  var min$2 = Math.min;
+  var MAX_UINT32 = 0xFFFFFFFF;
+
+  // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
+  // Weex JS has frozen built-in prototypes, so use try / catch wrapper
+  var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
+    // eslint-disable-next-line regexp/no-empty-group -- required for testing
+    var re = /(?:)/;
+    var originalExec = re.exec;
+    re.exec = function () { return originalExec.apply(this, arguments); };
+    var result = 'ab'.split(re);
+    return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
+  });
+
+  // @@split logic
+  fixRegexpWellKnownSymbolLogic('split', function (SPLIT, nativeSplit, maybeCallNative) {
+    var internalSplit;
+    if (
+      'abbc'.split(/(b)*/)[1] == 'c' ||
+      // eslint-disable-next-line regexp/no-empty-group -- required for testing
+      'test'.split(/(?:)/, -1).length != 4 ||
+      'ab'.split(/(?:ab)*/).length != 2 ||
+      '.'.split(/(.?)(.?)/).length != 4 ||
+      // eslint-disable-next-line regexp/no-assertion-capturing-group, regexp/no-empty-group -- required for testing
+      '.'.split(/()()/).length > 1 ||
+      ''.split(/.?/).length
+    ) {
+      // based on es5-shim implementation, need to rework it
+      internalSplit = function (separator, limit) {
+        var string = toString_1(requireObjectCoercible(this));
+        var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
+        if (lim === 0) return [];
+        if (separator === undefined) return [string];
+        // If `separator` is not a regex, use native split
+        if (!isRegexp(separator)) {
+          return nativeSplit.call(string, separator, lim);
+        }
+        var output = [];
+        var flags = (separator.ignoreCase ? 'i' : '') +
+                    (separator.multiline ? 'm' : '') +
+                    (separator.unicode ? 'u' : '') +
+                    (separator.sticky ? 'y' : '');
+        var lastLastIndex = 0;
+        // Make `global` and avoid `lastIndex` issues by working with a copy
+        var separatorCopy = new RegExp(separator.source, flags + 'g');
+        var match, lastIndex, lastLength;
+        while (match = regexpExec.call(separatorCopy, string)) {
+          lastIndex = separatorCopy.lastIndex;
+          if (lastIndex > lastLastIndex) {
+            output.push(string.slice(lastLastIndex, match.index));
+            if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
+            lastLength = match[0].length;
+            lastLastIndex = lastIndex;
+            if (output.length >= lim) break;
+          }
+          if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
+        }
+        if (lastLastIndex === string.length) {
+          if (lastLength || !separatorCopy.test('')) output.push('');
+        } else output.push(string.slice(lastLastIndex));
+        return output.length > lim ? output.slice(0, lim) : output;
+      };
+    // Chakra, V8
+    } else if ('0'.split(undefined, 0).length) {
+      internalSplit = function (separator, limit) {
+        return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
+      };
+    } else internalSplit = nativeSplit;
+
+    return [
+      // `String.prototype.split` method
+      // https://tc39.es/ecma262/#sec-string.prototype.split
+      function split(separator, limit) {
+        var O = requireObjectCoercible(this);
+        var splitter = separator == undefined ? undefined : separator[SPLIT];
+        return splitter !== undefined
+          ? splitter.call(separator, O, limit)
+          : internalSplit.call(toString_1(O), separator, limit);
+      },
+      // `RegExp.prototype[@@split]` method
+      // https://tc39.es/ecma262/#sec-regexp.prototype-@@split
+      //
+      // NOTE: This cannot be properly polyfilled in engines that don't support
+      // the 'y' flag.
+      function (string, limit) {
+        var rx = anObject(this);
+        var S = toString_1(string);
+        var res = maybeCallNative(internalSplit, rx, S, limit, internalSplit !== nativeSplit);
+
+        if (res.done) return res.value;
+
+        var C = speciesConstructor(rx, RegExp);
+
+        var unicodeMatching = rx.unicode;
+        var flags = (rx.ignoreCase ? 'i' : '') +
+                    (rx.multiline ? 'm' : '') +
+                    (rx.unicode ? 'u' : '') +
+                    (UNSUPPORTED_Y ? 'g' : 'y');
+
+        // ^(? + rx + ) is needed, in combination with some S slicing, to
+        // simulate the 'y' flag.
+        var splitter = new C(UNSUPPORTED_Y ? '^(?:' + rx.source + ')' : rx, flags);
+        var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
+        if (lim === 0) return [];
+        if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];
+        var p = 0;
+        var q = 0;
+        var A = [];
+        while (q < S.length) {
+          splitter.lastIndex = UNSUPPORTED_Y ? 0 : q;
+          var z = regexpExecAbstract(splitter, UNSUPPORTED_Y ? S.slice(q) : S);
+          var e;
+          if (
+            z === null ||
+            (e = min$2(toLength(splitter.lastIndex + (UNSUPPORTED_Y ? q : 0)), S.length)) === p
+          ) {
+            q = advanceStringIndex(S, q, unicodeMatching);
+          } else {
+            A.push(S.slice(p, q));
+            if (A.length === lim) return A;
+            for (var i = 1; i <= z.length - 1; i++) {
+              A.push(z[i]);
+              if (A.length === lim) return A;
+            }
+            q = p = e;
+          }
+        }
+        A.push(S.slice(p));
+        return A;
+      }
+    ];
+  }, !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC, UNSUPPORTED_Y);
+
   /**
    * Append a class to an element
    *
@@ -1626,46 +1586,31 @@
    * @param {String} className
    * @returns null
    */
-  function _addClass(element, className) {
+
+  function addClass(element, className) {
     if (element instanceof SVGElement) {
       // svg
-      var pre = element.getAttribute('class') || '';
+      var pre = element.getAttribute("class") || "";
 
-      element.setAttribute('class', pre + ' ' + className);
+      if (!pre.match(className)) {
+        // check if element doesn't already have className
+        element.setAttribute("class", "".concat(pre, " ").concat(className));
+      }
     } else {
       if (element.classList !== undefined) {
         // check for modern classList property
-        var classes = className.split(' ');
-        _forEach(classes, function (cls) {
-          element.classList.add( cls );
+        var classes = className.split(" ");
+        forEach(classes, function (cls) {
+          element.classList.add(cls);
         });
-      } else if (!element.className.match( className )) {
+      } else if (!element.className.match(className)) {
         // check if element doesn't already have className
-        element.className += ' ' + className;
+        element.className += " ".concat(className);
       }
     }
   }
 
   /**
-   * Remove a class from an element
-   *
-   * @api private
-   * @method _removeClass
-   * @param {Object} element
-   * @param {RegExp|String} classNameRegex can be regex or string
-   * @returns null
-   */
-  function _removeClass(element, classNameRegex) {
-    if (element instanceof SVGElement) {
-      var pre = element.getAttribute('class') || '';
-
-      element.setAttribute('class', pre.replace(classNameRegex, '').replace(/^\s+|\s+$/g, ''));
-    } else {
-      element.className = element.className.replace(classNameRegex, '').replace(/^\s+|\s+$/g, '');
-    }
-  }
-
-  /**
    * Get an element CSS property on the page
    * Thanks to JavaScript Kit: http://www.javascriptkit.com/dhtmltutors/dhtmlcascade4.shtml
    *
@@ -1673,17 +1618,20 @@
    * @method _getPropValue
    * @param {Object} element
    * @param {String} propName
-   * @returns Element's property value
+   * @returns string property value
    */
-  function _getPropValue (element, propName) {
-    var propValue = '';
-    if (element.currentStyle) { //IE
-      propValue = element.currentStyle[propName];
-    } else if (document.defaultView && document.defaultView.getComputedStyle) { //Others
-      propValue = document.defaultView.getComputedStyle(element, null).getPropertyValue(propName);
-    }
+  function getPropValue(element, propName) {
+    var propValue = "";
 
-    //Prevent exception in IE
+    if (element.currentStyle) {
+      //IE
+      propValue = element.currentStyle[propName];
+    } else if (document.defaultView && document.defaultView.getComputedStyle) {
+      //Others
+      propValue = document.defaultView.getComputedStyle(element, null).getPropertyValue(propName);
+    } //Prevent exception in IE
+
+
     if (propValue && propValue.toLowerCase) {
       return propValue.toLowerCase();
     } else {
@@ -1692,25 +1640,63 @@
   }
 
   /**
-   * Checks to see if target element (or parents) position is fixed or not
+   * To set the show element
+   * This function set a relative (in most cases) position and changes the z-index
    *
    * @api private
-   * @method _isFixed
-   * @param {Object} element
-   * @returns Boolean
+   * @method _setShowElement
+   * @param {Object} targetElement
    */
-  function _isFixed (element) {
-    var p = element.parentNode;
 
-    if (!p || p.nodeName === 'HTML') {
-      return false;
+  function setShowElement(_ref) {
+    var element = _ref.element;
+    addClass(element, "introjs-showElement");
+    var currentElementPosition = getPropValue(element, "position");
+
+    if (currentElementPosition !== "absolute" && currentElementPosition !== "relative" && currentElementPosition !== "sticky" && currentElementPosition !== "fixed") {
+      //change to new intro item
+      addClass(element, "introjs-relativePosition");
+    }
+  }
+
+  /**
+   * Find the nearest scrollable parent
+   * copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent
+   *
+   * @param Element element
+   * @return Element
+   */
+  function getScrollParent(element) {
+    var style = window.getComputedStyle(element);
+    var excludeStaticParent = style.position === "absolute";
+    var overflowRegex = /(auto|scroll)/;
+    if (style.position === "fixed") return document.body;
+
+    for (var parent = element; parent = parent.parentElement;) {
+      style = window.getComputedStyle(parent);
+
+      if (excludeStaticParent && style.position === "static") {
+        continue;
+      }
+
+      if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;
     }
 
-    if (_getPropValue(element, 'position') === 'fixed') {
-      return true;
-    }
+    return document.body;
+  }
 
-    return _isFixed(p);
+  /**
+   * scroll a scrollable element to a child element
+   *
+   * @param {Object} targetElement
+   */
+
+  function scrollParentToElement(targetElement) {
+    var element = targetElement.element;
+    if (!this._options.scrollToElement) return;
+    var parent = getScrollParent(element);
+    if (parent === document.body) return;
+    parent.scrollTop = element.offsetTop - parent.offsetTop;
   }
 
   /**
@@ -1721,12 +1707,18 @@
    * @method _getWinSize
    * @returns {Object} width and height attributes
    */
-  function _getWinSize() {
+  function getWinSize() {
     if (window.innerWidth !== undefined) {
-      return { width: window.innerWidth, height: window.innerHeight };
+      return {
+        width: window.innerWidth,
+        height: window.innerHeight
+      };
     } else {
       var D = document.documentElement;
-      return { width: D.clientWidth, height: D.clientHeight };
+      return {
+        width: D.clientWidth,
+        height: D.clientHeight
+      };
     }
   }
 
@@ -1738,547 +1730,1092 @@
    * @method _elementInViewport
    * @param {Object} el
    */
-  function _elementInViewport(el) {
+  function elementInViewport(el) {
     var rect = el.getBoundingClientRect();
-
-    return (
-      rect.top >= 0 &&
-      rect.left >= 0 &&
-      (rect.bottom+80) <= window.innerHeight && // add 80 to get the text right
-      rect.right <= window.innerWidth
-    );
+    return rect.top >= 0 && rect.left >= 0 && rect.bottom + 80 <= window.innerHeight && // add 80 to get the text right
+    rect.right <= window.innerWidth;
   }
 
   /**
-   * Add overlay layer to the page
+   * To change the scroll of `window` after highlighting an element
    *
    * @api private
-   * @method _addOverlayLayer
-   * @param {Object} targetElm
+   * @param {String} scrollTo
+   * @param {Object} targetElement
+   * @param {Object} tooltipLayer
    */
-  function _addOverlayLayer(targetElm) {
-    var overlayLayer = document.createElement('div'),
-        styleText = '',
-        self = this;
 
-    //set css class name
-    overlayLayer.className = 'introjs-overlay';
+  function scrollTo(scrollTo, _ref, tooltipLayer) {
+    var element = _ref.element;
+    if (scrollTo === "off") return;
+    var rect;
+    if (!this._options.scrollToElement) return;
 
-    //check if the target element is body, we should calculate the size of overlay layer in a better way
-    if (!targetElm.tagName || targetElm.tagName.toLowerCase() === 'body') {
-      styleText += 'top: 0;bottom: 0; left: 0;right: 0;position: fixed;';
-      overlayLayer.style.cssText = styleText;
+    if (scrollTo === "tooltip") {
+      rect = tooltipLayer.getBoundingClientRect();
     } else {
-      //set overlay layer position
-      var elementPosition = _getOffset(targetElm);
-      if (elementPosition) {
-        styleText += 'width: ' + elementPosition.width + 'px; height:' + elementPosition.height + 'px; top:' + elementPosition.top + 'px;left: ' + elementPosition.left + 'px;';
-        overlayLayer.style.cssText = styleText;
-      }
+      rect = element.getBoundingClientRect();
     }
 
-    targetElm.appendChild(overlayLayer);
+    if (!elementInViewport(element)) {
+      var winHeight = getWinSize().height;
+      var top = rect.bottom - (rect.bottom - rect.top); // TODO (afshinm): do we need scroll padding now?
+      // I have changed the scroll option and now it scrolls the window to
+      // the center of the target element or tooltip.
 
-    overlayLayer.onclick = function() {
-      if (self._options.exitOnOverlayClick === true) {
-        _exitIntro.call(self, targetElm);
+      if (top < 0 || element.clientHeight > winHeight) {
+        window.scrollBy(0, rect.top - (winHeight / 2 - rect.height / 2) - this._options.scrollPadding); // 30px padding from edge to look nice
+        //Scroll down
+      } else {
+        window.scrollBy(0, rect.top - (winHeight / 2 - rect.height / 2) + this._options.scrollPadding); // 30px padding from edge to look nice
       }
-    };
-
-    window.setTimeout(function() {
-      styleText += 'opacity: ' + self._options.overlayOpacity.toString() + ';';
-      overlayLayer.style.cssText = styleText;
-    }, 10);
-
-    return true;
-  }
-
-  /**
-   * Removes open hint (tooltip hint)
-   *
-   * @api private
-   * @method _removeHintTooltip
-   */
-  function _removeHintTooltip() {
-    var tooltip = document.querySelector('.introjs-hintReference');
-
-    if (tooltip) {
-      var step = tooltip.getAttribute('data-step');
-      tooltip.parentNode.removeChild(tooltip);
-      return step;
     }
   }
 
   /**
-   * Start parsing hint items
+   * Setting anchors to behave like buttons
    *
    * @api private
-   * @param {Object} targetElm
-   * @method _startHint
+   * @method _setAnchorAsButton
    */
-  function _populateHints(targetElm) {
+  function setAnchorAsButton(anchor) {
+    anchor.setAttribute("role", "button");
+    anchor.tabIndex = 0;
+  }
 
-    this._introItems = [];
+  // eslint-disable-next-line es/no-object-assign -- safe
+  var $assign = Object.assign;
+  // eslint-disable-next-line es/no-object-defineproperty -- required for testing
+  var defineProperty = Object.defineProperty;
 
-    if (this._options.hints) {
-      _forEach(this._options.hints, function (hint) {
-        var currentItem = _cloneObject(hint);
-
-        if (typeof(currentItem.element) === 'string') {
-          //grab the element with given selector from the page
-          currentItem.element = document.querySelector(currentItem.element);
-        }
-
-        currentItem.hintPosition = currentItem.hintPosition || this._options.hintPosition;
-        currentItem.hintAnimation = currentItem.hintAnimation || this._options.hintAnimation;
-
-        if (currentItem.element !== null) {
-          this._introItems.push(currentItem);
-        }
-      }.bind(this));
-    } else {
-      var hints = targetElm.querySelectorAll('*[data-hint]');
-
-      if (!hints || !hints.length) {
-        return false;
-      }
-
-      //first add intro items with data-step
-      _forEach(hints, function (currentElement) {
-        // hint animation
-        var hintAnimation = currentElement.getAttribute('data-hintanimation');
-
-        if (hintAnimation) {
-          hintAnimation = (hintAnimation === 'true');
-        } else {
-          hintAnimation = this._options.hintAnimation;
-        }
-
-        this._introItems.push({
-          element: currentElement,
-          hint: currentElement.getAttribute('data-hint'),
-          hintPosition: currentElement.getAttribute('data-hintposition') || this._options.hintPosition,
-          hintAnimation: hintAnimation,
-          tooltipClass: currentElement.getAttribute('data-tooltipclass'),
-          position: currentElement.getAttribute('data-position') || this._options.tooltipPosition
+  // `Object.assign` method
+  // https://tc39.es/ecma262/#sec-object.assign
+  var objectAssign = !$assign || fails(function () {
+    // should have correct order of operations (Edge bug)
+    if (descriptors && $assign({ b: 1 }, $assign(defineProperty({}, 'a', {
+      enumerable: true,
+      get: function () {
+        defineProperty(this, 'b', {
+          value: 3,
+          enumerable: false
         });
-      }.bind(this));
-    }
-
-    _addHints.call(this);
-
-    /* 
-    todo:
-    these events should be removed at some point 
-    */
-    DOMEvent.on(document, 'click', _removeHintTooltip, this, false);
-    DOMEvent.on(window, 'resize', _reAlignHints, this, true);
-  }
-
-  /**
-   * Re-aligns all hint elements
-   *
-   * @api private
-   * @method _reAlignHints
-   */
-  function _reAlignHints() {
-    _forEach(this._introItems, function (item) {
-      if (typeof(item.targetElement) === 'undefined') {
-        return;
       }
-
-      _alignHintPosition.call(this, item.hintPosition, item.element, item.targetElement);
-    }.bind(this));
-  }
-
-  /**
-  * Get a queryselector within the hint wrapper
-  *
-  * @param {String} selector
-  * @return {NodeList|Array}
-  */
-  function _hintQuerySelectorAll(selector) {
-    var hintsWrapper = document.querySelector('.introjs-hints');
-    return (hintsWrapper) ? hintsWrapper.querySelectorAll(selector) : [];
-  }
-
-  /**
-   * Hide a hint
-   *
-   * @api private
-   * @method _hideHint
-   */
-  function _hideHint(stepId) {
-    var hint = _hintQuerySelectorAll('.introjs-hint[data-step="' + stepId + '"]')[0];
-    
-    _removeHintTooltip.call(this);
-
-    if (hint) {
-      _addClass(hint, 'introjs-hidehint');
-    }
-
-    // call the callback function (if any)
-    if (typeof (this._hintCloseCallback) !== 'undefined') {
-      this._hintCloseCallback.call(this, stepId);
-    }
-  }
-
-  /**
-   * Hide all hints
-   *
-   * @api private
-   * @method _hideHints
-   */
-  function _hideHints() {
-    var hints = _hintQuerySelectorAll('.introjs-hint');
-
-    _forEach(hints, function (hint) {
-      _hideHint.call(this, hint.getAttribute('data-step'));
-    }.bind(this));
-  }
-
-  /**
-   * Show all hints
-   *
-   * @api private
-   * @method _showHints
-   */
-  function _showHints() {
-    var hints = _hintQuerySelectorAll('.introjs-hint');
-
-    if (hints && hints.length) {
-      _forEach(hints, function (hint) {
-        _showHint.call(this, hint.getAttribute('data-step'));
-      }.bind(this));
-    } else {
-      _populateHints.call(this, this._targetElement);
-    }
-  }
-
-  /**
-   * Show a hint
-   *
-   * @api private
-   * @method _showHint
-   */
-  function _showHint(stepId) {
-    var hint = _hintQuerySelectorAll('.introjs-hint[data-step="' + stepId + '"]')[0];
-
-    if (hint) {
-      _removeClass(hint, /introjs-hidehint/g);
-    }
-  }
-
-  /**
-   * Removes all hint elements on the page
-   * Useful when you want to destroy the elements and add them again (e.g. a modal or popup)
-   *
-   * @api private
-   * @method _removeHints
-   */
-  function _removeHints() {
-    var hints = _hintQuerySelectorAll('.introjs-hint');
-
-    _forEach(hints, function (hint) {
-      _removeHint.call(this, hint.getAttribute('data-step'));
-    }.bind(this));
-  }
-
-  /**
-   * Remove one single hint element from the page
-   * Useful when you want to destroy the element and add them again (e.g. a modal or popup)
-   * Use removeHints if you want to remove all elements.
-   *
-   * @api private
-   * @method _removeHint
-   */
-  function _removeHint(stepId) {
-    var hint = _hintQuerySelectorAll('.introjs-hint[data-step="' + stepId + '"]')[0];
-
-    if (hint) {
-      hint.parentNode.removeChild(hint);
-    }
-  }
-
-  /**
-   * Add all available hints to the page
-   *
-   * @api private
-   * @method _addHints
-   */
-  function _addHints() {
-    var self = this;
-
-    var hintsWrapper = document.querySelector('.introjs-hints');
-
-    if (hintsWrapper === null) {
-      hintsWrapper = document.createElement('div');
-      hintsWrapper.className = 'introjs-hints';
-    }
-
-    /**
-    * Returns an event handler unique to the hint iteration
-    * 
-    * @param {Integer} i
-    * @return {Function}
-    */
-    var getHintClick = function (i) {
-      return function(e) {
-        var evt = e ? e : window.event;
-        
-        if (evt.stopPropagation) {
-          evt.stopPropagation();
-        }
-
-        if (evt.cancelBubble !== null) {
-          evt.cancelBubble = true;
-        }
-
-        _showHintDialog.call(self, i);
-      };
-    };
-
-    _forEach(this._introItems, function(item, i) {
-      // avoid append a hint twice
-      if (document.querySelector('.introjs-hint[data-step="' + i + '"]')) {
-        return;
+    }), { b: 2 })).b !== 1) return true;
+    // should work with symbols and should have deterministic property order (V8 bug)
+    var A = {};
+    var B = {};
+    // eslint-disable-next-line es/no-symbol -- safe
+    var symbol = Symbol();
+    var alphabet = 'abcdefghijklmnopqrst';
+    A[symbol] = 7;
+    alphabet.split('').forEach(function (chr) { B[chr] = chr; });
+    return $assign({}, A)[symbol] != 7 || objectKeys($assign({}, B)).join('') != alphabet;
+  }) ? function assign(target, source) { // eslint-disable-line no-unused-vars -- required for `.length`
+    var T = toObject(target);
+    var argumentsLength = arguments.length;
+    var index = 1;
+    var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
+    var propertyIsEnumerable = objectPropertyIsEnumerable.f;
+    while (argumentsLength > index) {
+      var S = indexedObject(arguments[index++]);
+      var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
+      var length = keys.length;
+      var j = 0;
+      var key;
+      while (length > j) {
+        key = keys[j++];
+        if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
       }
+    } return T;
+  } : $assign;
 
-      var hint = document.createElement('a');
-      _setAnchorAsButton(hint);
-
-      hint.onclick = getHintClick(i);
-
-      hint.className = 'introjs-hint';
-
-      if (!item.hintAnimation) {
-        _addClass(hint, 'introjs-hint-no-anim');
-      }
-
-      // hint's position should be fixed if the target element's position is fixed
-      if (_isFixed(item.element)) {
-        _addClass(hint, 'introjs-fixedhint');
-      }
-
-      var hintDot = document.createElement('div');
-      hintDot.className = 'introjs-hint-dot';
-      var hintPulse = document.createElement('div');
-      hintPulse.className = 'introjs-hint-pulse';
-
-      hint.appendChild(hintDot);
-      hint.appendChild(hintPulse);
-      hint.setAttribute('data-step', i);
-
-      // we swap the hint element with target element
-      // because _setHelperLayerPosition uses `element` property
-      item.targetElement = item.element;
-      item.element = hint;
-
-      // align the hint position
-      _alignHintPosition.call(this, item.hintPosition, hint, item.targetElement);
-
-      hintsWrapper.appendChild(hint);
-    }.bind(this));
-
-    // adding the hints wrapper
-    document.body.appendChild(hintsWrapper);
-
-    // call the callback function (if any)
-    if (typeof (this._hintsAddedCallback) !== 'undefined') {
-      this._hintsAddedCallback.call(this);
-    }
-  }
+  // `Object.assign` method
+  // https://tc39.es/ecma262/#sec-object.assign
+  // eslint-disable-next-line es/no-object-assign -- required for testing
+  _export({ target: 'Object', stat: true, forced: Object.assign !== objectAssign }, {
+    assign: objectAssign
+  });
 
   /**
-   * Aligns hint position
+   * Checks to see if target element (or parents) position is fixed or not
    *
    * @api private
-   * @method _alignHintPosition
-   * @param {String} position
-   * @param {Object} hint
+   * @method _isFixed
    * @param {Object} element
+   * @returns Boolean
    */
-  function _alignHintPosition(position, hint, element) {
-    // get/calculate offset of target element
-    var offset = _getOffset.call(this, element);
-    var iconWidth = 20;
-    var iconHeight = 20;
 
-    // align the hint element
-    switch (position) {
-      default:
-      case 'top-left':
-        hint.style.left = offset.left + 'px';
-        hint.style.top = offset.top + 'px';
-        break;
-      case 'top-right':
-        hint.style.left = (offset.left + offset.width - iconWidth) + 'px';
-        hint.style.top = offset.top + 'px';
-        break;
-      case 'bottom-left':
-        hint.style.left = offset.left + 'px';
-        hint.style.top = (offset.top + offset.height - iconHeight) + 'px';
-        break;
-      case 'bottom-right':
-        hint.style.left = (offset.left + offset.width - iconWidth) + 'px';
-        hint.style.top = (offset.top + offset.height - iconHeight) + 'px';
-        break;
-      case 'middle-left':
-        hint.style.left = offset.left + 'px';
-        hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px';
-        break;
-      case 'middle-right':
-        hint.style.left = (offset.left + offset.width - iconWidth) + 'px';
-        hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px';
-        break;
-      case 'middle-middle':
-        hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px';
-        hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px';
-        break;
-      case 'bottom-middle':
-        hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px';
-        hint.style.top = (offset.top + offset.height - iconHeight) + 'px';
-        break;
-      case 'top-middle':
-        hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px';
-        hint.style.top = offset.top + 'px';
-        break;
+  function isFixed(element) {
+    var p = element.parentNode;
+
+    if (!p || p.nodeName === "HTML") {
+      return false;
     }
+
+    if (getPropValue(element, "position") === "fixed") {
+      return true;
+    }
+
+    return isFixed(p);
   }
 
   /**
-   * Triggers when user clicks on the hint element
-   *
-   * @api private
-   * @method _showHintDialog
-   * @param {Number} stepId
-   */
-  function _showHintDialog(stepId) {
-    var hintElement = document.querySelector('.introjs-hint[data-step="' + stepId + '"]');
-    var item = this._introItems[stepId];
-
-    // call the callback function (if any)
-    if (typeof (this._hintClickCallback) !== 'undefined') {
-      this._hintClickCallback.call(this, hintElement, item, stepId);
-    }
-
-    // remove all open tooltips
-    var removedStep = _removeHintTooltip.call(this);
-
-    // to toggle the tooltip
-    if (parseInt(removedStep, 10) === stepId) {
-      return;
-    }
-
-    var tooltipLayer = document.createElement('div');
-    var tooltipTextLayer = document.createElement('div');
-    var arrowLayer = document.createElement('div');
-    var referenceLayer = document.createElement('div');
-
-    tooltipLayer.className = 'introjs-tooltip';
-
-    tooltipLayer.onclick = function (e) {
-      //IE9 & Other Browsers
-      if (e.stopPropagation) {
-        e.stopPropagation();
-      }
-      //IE8 and Lower
-      else {
-        e.cancelBubble = true;
-      }
-    };
-
-    tooltipTextLayer.className = 'introjs-tooltiptext';
-
-    var tooltipWrapper = document.createElement('p');
-    tooltipWrapper.innerHTML = item.hint;
-
-    var closeButton = document.createElement('a');
-    closeButton.className = this._options.buttonClass;
-    closeButton.setAttribute('role', 'button');
-    closeButton.innerHTML = this._options.hintButtonLabel;
-    closeButton.onclick = _hideHint.bind(this, stepId);
-
-    tooltipTextLayer.appendChild(tooltipWrapper);
-    tooltipTextLayer.appendChild(closeButton);
-
-    arrowLayer.className = 'introjs-arrow';
-    tooltipLayer.appendChild(arrowLayer);
-
-    tooltipLayer.appendChild(tooltipTextLayer);
-
-    // set current step for _placeTooltip function
-    this._currentStep = hintElement.getAttribute('data-step');
-
-    // align reference layer position
-    referenceLayer.className = 'introjs-tooltipReferenceLayer introjs-hintReference';
-    referenceLayer.setAttribute('data-step', hintElement.getAttribute('data-step'));
-    _setHelperLayerPosition.call(this, referenceLayer);
-
-    referenceLayer.appendChild(tooltipLayer);
-    document.body.appendChild(referenceLayer);
-
-    //set proper position
-    _placeTooltip.call(this, hintElement, tooltipLayer, arrowLayer, null, true);
-  }
-
-  /**
-   * Get an element position on the page
+   * Get an element position on the page relative to another element (or body)
    * Thanks to `meouw`: http://stackoverflow.com/a/442474/375966
    *
    * @api private
-   * @method _getOffset
+   * @method getOffset
    * @param {Object} element
+   * @param {Object} relativeEl
    * @returns Element's position info
    */
-  function _getOffset(element) {
+
+  function getOffset(element, relativeEl) {
     var body = document.body;
     var docEl = document.documentElement;
     var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
     var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
+    relativeEl = relativeEl || body;
     var x = element.getBoundingClientRect();
-    return {
-      top: x.top + scrollTop,
+    var xr = relativeEl.getBoundingClientRect();
+    var relativeElPosition = getPropValue(relativeEl, "position");
+    var obj = {
       width: x.width,
-      height: x.height,
-      left: x.left + scrollLeft
+      height: x.height
     };
+
+    if (relativeEl.tagName.toLowerCase() !== "body" && relativeElPosition === "relative" || relativeElPosition === "sticky") {
+      // when the container of our target element is _not_ body and has either "relative" or "sticky" position, we should not
+      // consider the scroll position but we need to include the relative x/y of the container element
+      return Object.assign(obj, {
+        top: x.top - xr.top,
+        left: x.left - xr.left
+      });
+    } else {
+      if (isFixed(element)) {
+        return Object.assign(obj, {
+          top: x.top,
+          left: x.left
+        });
+      } else {
+        return Object.assign(obj, {
+          top: x.top + scrollTop,
+          left: x.left + scrollLeft
+        });
+      }
+    }
+  }
+
+  var floor$1 = Math.floor;
+  var replace = ''.replace;
+  var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d{1,2}|<[^>]*>)/g;
+  var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d{1,2})/g;
+
+  // `GetSubstitution` abstract operation
+  // https://tc39.es/ecma262/#sec-getsubstitution
+  var getSubstitution = function (matched, str, position, captures, namedCaptures, replacement) {
+    var tailPos = position + matched.length;
+    var m = captures.length;
+    var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
+    if (namedCaptures !== undefined) {
+      namedCaptures = toObject(namedCaptures);
+      symbols = SUBSTITUTION_SYMBOLS;
+    }
+    return replace.call(replacement, symbols, function (match, ch) {
+      var capture;
+      switch (ch.charAt(0)) {
+        case '$': return '$';
+        case '&': return matched;
+        case '`': return str.slice(0, position);
+        case "'": return str.slice(tailPos);
+        case '<':
+          capture = namedCaptures[ch.slice(1, -1)];
+          break;
+        default: // \d\d?
+          var n = +ch;
+          if (n === 0) return match;
+          if (n > m) {
+            var f = floor$1(n / 10);
+            if (f === 0) return match;
+            if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
+            return match;
+          }
+          capture = captures[n - 1];
+      }
+      return capture === undefined ? '' : capture;
+    });
+  };
+
+  var REPLACE = wellKnownSymbol('replace');
+  var max$2 = Math.max;
+  var min$1 = Math.min;
+
+  var maybeToString = function (it) {
+    return it === undefined ? it : String(it);
+  };
+
+  // IE <= 11 replaces $0 with the whole match, as if it was $&
+  // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
+  var REPLACE_KEEPS_$0 = (function () {
+    // eslint-disable-next-line regexp/prefer-escape-replacement-dollar-char -- required for testing
+    return 'a'.replace(/./, '$0') === '$0';
+  })();
+
+  // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string
+  var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {
+    if (/./[REPLACE]) {
+      return /./[REPLACE]('a', '$0') === '';
+    }
+    return false;
+  })();
+
+  var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
+    var re = /./;
+    re.exec = function () {
+      var result = [];
+      result.groups = { a: '7' };
+      return result;
+    };
+    return ''.replace(re, '$<a>') !== '7';
+  });
+
+  // @@replace logic
+  fixRegexpWellKnownSymbolLogic('replace', function (_, nativeReplace, maybeCallNative) {
+    var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';
+
+    return [
+      // `String.prototype.replace` method
+      // https://tc39.es/ecma262/#sec-string.prototype.replace
+      function replace(searchValue, replaceValue) {
+        var O = requireObjectCoercible(this);
+        var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
+        return replacer !== undefined
+          ? replacer.call(searchValue, O, replaceValue)
+          : nativeReplace.call(toString_1(O), searchValue, replaceValue);
+      },
+      // `RegExp.prototype[@@replace]` method
+      // https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
+      function (string, replaceValue) {
+        var rx = anObject(this);
+        var S = toString_1(string);
+
+        if (
+          typeof replaceValue === 'string' &&
+          replaceValue.indexOf(UNSAFE_SUBSTITUTE) === -1 &&
+          replaceValue.indexOf('$<') === -1
+        ) {
+          var res = maybeCallNative(nativeReplace, rx, S, replaceValue);
+          if (res.done) return res.value;
+        }
+
+        var functionalReplace = typeof replaceValue === 'function';
+        if (!functionalReplace) replaceValue = toString_1(replaceValue);
+
+        var global = rx.global;
+        if (global) {
+          var fullUnicode = rx.unicode;
+          rx.lastIndex = 0;
+        }
+        var results = [];
+        while (true) {
+          var result = regexpExecAbstract(rx, S);
+          if (result === null) break;
+
+          results.push(result);
+          if (!global) break;
+
+          var matchStr = toString_1(result[0]);
+          if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
+        }
+
+        var accumulatedResult = '';
+        var nextSourcePosition = 0;
+        for (var i = 0; i < results.length; i++) {
+          result = results[i];
+
+          var matched = toString_1(result[0]);
+          var position = max$2(min$1(toInteger(result.index), S.length), 0);
+          var captures = [];
+          // NOTE: This is equivalent to
+          //   captures = result.slice(1).map(maybeToString)
+          // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
+          // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
+          // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
+          for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
+          var namedCaptures = result.groups;
+          if (functionalReplace) {
+            var replacerArgs = [matched].concat(captures, position, S);
+            if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
+            var replacement = toString_1(replaceValue.apply(undefined, replacerArgs));
+          } else {
+            replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
+          }
+          if (position >= nextSourcePosition) {
+            accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
+            nextSourcePosition = position + matched.length;
+          }
+        }
+        return accumulatedResult + S.slice(nextSourcePosition);
+      }
+    ];
+  }, !REPLACE_SUPPORTS_NAMED_GROUPS || !REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE);
+
+  /**
+   * Remove a class from an element
+   *
+   * @api private
+   * @method _removeClass
+   * @param {Object} element
+   * @param {RegExp|String} classNameRegex can be regex or string
+   * @returns null
+   */
+  function removeClass(element, classNameRegex) {
+    if (element instanceof SVGElement) {
+      var pre = element.getAttribute("class") || "";
+      element.setAttribute("class", pre.replace(classNameRegex, "").replace(/^\s+|\s+$/g, ""));
+    } else {
+      element.className = element.className.replace(classNameRegex, "").replace(/^\s+|\s+$/g, "");
+    }
   }
 
   /**
-  * Find the nearest scrollable parent
-  * copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent
-  *
-  * @param Element element
-  * @return Element
-  */
-  function _getScrollParent(element) {
-    var style = window.getComputedStyle(element);
-    var excludeStaticParent = (style.position === "absolute");
-    var overflowRegex = /(auto|scroll)/;
+   * Sets the style of an DOM element
+   *
+   * @param {Object} element
+   * @param {Object|string} style
+   * @return null
+   */
+  function setStyle(element, style) {
+    var cssText = "";
 
-    if (style.position === "fixed") return document.body;
-    
-    for (var parent = element; (parent = parent.parentElement);) {
-      style = window.getComputedStyle(parent);
-      if (excludeStaticParent && style.position === "static") {
-        continue;
-      }
-      if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;
+    if (element.style.cssText) {
+      cssText += element.style.cssText;
     }
 
-    return document.body;
+    if (typeof style === "string") {
+      cssText += style;
+    } else {
+      for (var rule in style) {
+        cssText += "".concat(rule, ":").concat(style[rule], ";");
+      }
+    }
+
+    element.style.cssText = cssText;
   }
 
   /**
-  * scroll a scrollable element to a child element
-  *
-  * @param Element parent
-  * @param Element element
-  * @return Null
-  */
-  function _scrollParentToElement (parent, element) {
-    parent.scrollTop = element.offsetTop - parent.offsetTop;
+   * Update the position of the helper layer on the screen
+   *
+   * @api private
+   * @method _setHelperLayerPosition
+   * @param {Object} helperLayer
+   */
+
+  function setHelperLayerPosition(helperLayer) {
+    if (helperLayer) {
+      //prevent error when `this._currentStep` in undefined
+      if (!this._introItems[this._currentStep]) return;
+      var currentElement = this._introItems[this._currentStep];
+      var elementPosition = getOffset(currentElement.element, this._targetElement);
+      var widthHeightPadding = this._options.helperElementPadding; // If the target element is fixed, the tooltip should be fixed as well.
+      // Otherwise, remove a fixed class that may be left over from the previous
+      // step.
+
+      if (isFixed(currentElement.element)) {
+        addClass(helperLayer, "introjs-fixedTooltip");
+      } else {
+        removeClass(helperLayer, "introjs-fixedTooltip");
+      }
+
+      if (currentElement.position === "floating") {
+        widthHeightPadding = 0;
+      } //set new position to helper layer
+
+
+      setStyle(helperLayer, {
+        width: "".concat(elementPosition.width + widthHeightPadding, "px"),
+        height: "".concat(elementPosition.height + widthHeightPadding, "px"),
+        top: "".concat(elementPosition.top - widthHeightPadding / 2, "px"),
+        left: "".concat(elementPosition.left - widthHeightPadding / 2, "px")
+      });
+    }
+  }
+
+  var UNSCOPABLES = wellKnownSymbol('unscopables');
+  var ArrayPrototype = Array.prototype;
+
+  // Array.prototype[@@unscopables]
+  // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
+  if (ArrayPrototype[UNSCOPABLES] == undefined) {
+    objectDefineProperty.f(ArrayPrototype, UNSCOPABLES, {
+      configurable: true,
+      value: objectCreate(null)
+    });
+  }
+
+  // add a key to Array.prototype[@@unscopables]
+  var addToUnscopables = function (key) {
+    ArrayPrototype[UNSCOPABLES][key] = true;
+  };
+
+  var $includes = arrayIncludes.includes;
+
+
+  // `Array.prototype.includes` method
+  // https://tc39.es/ecma262/#sec-array.prototype.includes
+  _export({ target: 'Array', proto: true }, {
+    includes: function includes(el /* , fromIndex = 0 */) {
+      return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
+    }
+  });
+
+  // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
+  addToUnscopables('includes');
+
+  var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('slice');
+
+  var SPECIES = wellKnownSymbol('species');
+  var nativeSlice = [].slice;
+  var max$1 = Math.max;
+
+  // `Array.prototype.slice` method
+  // https://tc39.es/ecma262/#sec-array.prototype.slice
+  // fallback for not array-like ES3 strings and DOM objects
+  _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 }, {
+    slice: function slice(start, end) {
+      var O = toIndexedObject(this);
+      var length = toLength(O.length);
+      var k = toAbsoluteIndex(start, length);
+      var fin = toAbsoluteIndex(end === undefined ? length : end, length);
+      // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
+      var Constructor, result, n;
+      if (isArray(O)) {
+        Constructor = O.constructor;
+        // cross-realm fallback
+        if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
+          Constructor = undefined;
+        } else if (isObject(Constructor)) {
+          Constructor = Constructor[SPECIES];
+          if (Constructor === null) Constructor = undefined;
+        }
+        if (Constructor === Array || Constructor === undefined) {
+          return nativeSlice.call(O, k, fin);
+        }
+      }
+      result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0));
+      for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);
+      result.length = n;
+      return result;
+    }
+  });
+
+  var notARegexp = function (it) {
+    if (isRegexp(it)) {
+      throw TypeError("The method doesn't accept regular expressions");
+    } return it;
+  };
+
+  var MATCH = wellKnownSymbol('match');
+
+  var correctIsRegexpLogic = function (METHOD_NAME) {
+    var regexp = /./;
+    try {
+      '/./'[METHOD_NAME](regexp);
+    } catch (error1) {
+      try {
+        regexp[MATCH] = false;
+        return '/./'[METHOD_NAME](regexp);
+      } catch (error2) { /* empty */ }
+    } return false;
+  };
+
+  // `String.prototype.includes` method
+  // https://tc39.es/ecma262/#sec-string.prototype.includes
+  _export({ target: 'String', proto: true, forced: !correctIsRegexpLogic('includes') }, {
+    includes: function includes(searchString /* , position = 0 */) {
+      return !!~toString_1(requireObjectCoercible(this))
+        .indexOf(toString_1(notARegexp(searchString)), arguments.length > 1 ? arguments[1] : undefined);
+    }
+  });
+
+  var arrayMethodIsStrict = function (METHOD_NAME, argument) {
+    var method = [][METHOD_NAME];
+    return !!method && fails(function () {
+      // eslint-disable-next-line no-useless-call,no-throw-literal -- required for testing
+      method.call(null, argument || function () { throw 1; }, 1);
+    });
+  };
+
+  var nativeJoin = [].join;
+
+  var ES3_STRINGS = indexedObject != Object;
+  var STRICT_METHOD$1 = arrayMethodIsStrict('join', ',');
+
+  // `Array.prototype.join` method
+  // https://tc39.es/ecma262/#sec-array.prototype.join
+  _export({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$1 }, {
+    join: function join(separator) {
+      return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
+    }
+  });
+
+  // optional / simple context binding
+  var functionBindContext = function (fn, that, length) {
+    aFunction(fn);
+    if (that === undefined) return fn;
+    switch (length) {
+      case 0: return function () {
+        return fn.call(that);
+      };
+      case 1: return function (a) {
+        return fn.call(that, a);
+      };
+      case 2: return function (a, b) {
+        return fn.call(that, a, b);
+      };
+      case 3: return function (a, b, c) {
+        return fn.call(that, a, b, c);
+      };
+    }
+    return function (/* ...args */) {
+      return fn.apply(that, arguments);
+    };
+  };
+
+  var push = [].push;
+
+  // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterReject }` methods implementation
+  var createMethod = function (TYPE) {
+    var IS_MAP = TYPE == 1;
+    var IS_FILTER = TYPE == 2;
+    var IS_SOME = TYPE == 3;
+    var IS_EVERY = TYPE == 4;
+    var IS_FIND_INDEX = TYPE == 6;
+    var IS_FILTER_REJECT = TYPE == 7;
+    var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
+    return function ($this, callbackfn, that, specificCreate) {
+      var O = toObject($this);
+      var self = indexedObject(O);
+      var boundFunction = functionBindContext(callbackfn, that, 3);
+      var length = toLength(self.length);
+      var index = 0;
+      var create = specificCreate || arraySpeciesCreate;
+      var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_REJECT ? create($this, 0) : undefined;
+      var value, result;
+      for (;length > index; index++) if (NO_HOLES || index in self) {
+        value = self[index];
+        result = boundFunction(value, index, O);
+        if (TYPE) {
+          if (IS_MAP) target[index] = result; // map
+          else if (result) switch (TYPE) {
+            case 3: return true;              // some
+            case 5: return value;             // find
+            case 6: return index;             // findIndex
+            case 2: push.call(target, value); // filter
+          } else switch (TYPE) {
+            case 4: return false;             // every
+            case 7: push.call(target, value); // filterReject
+          }
+        }
+      }
+      return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
+    };
+  };
+
+  var arrayIteration = {
+    // `Array.prototype.forEach` method
+    // https://tc39.es/ecma262/#sec-array.prototype.foreach
+    forEach: createMethod(0),
+    // `Array.prototype.map` method
+    // https://tc39.es/ecma262/#sec-array.prototype.map
+    map: createMethod(1),
+    // `Array.prototype.filter` method
+    // https://tc39.es/ecma262/#sec-array.prototype.filter
+    filter: createMethod(2),
+    // `Array.prototype.some` method
+    // https://tc39.es/ecma262/#sec-array.prototype.some
+    some: createMethod(3),
+    // `Array.prototype.every` method
+    // https://tc39.es/ecma262/#sec-array.prototype.every
+    every: createMethod(4),
+    // `Array.prototype.find` method
+    // https://tc39.es/ecma262/#sec-array.prototype.find
+    find: createMethod(5),
+    // `Array.prototype.findIndex` method
+    // https://tc39.es/ecma262/#sec-array.prototype.findIndex
+    findIndex: createMethod(6),
+    // `Array.prototype.filterReject` method
+    // https://github.com/tc39/proposal-array-filtering
+    filterReject: createMethod(7)
+  };
+
+  var $filter = arrayIteration.filter;
+
+
+  var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('filter');
+
+  // `Array.prototype.filter` method
+  // https://tc39.es/ecma262/#sec-array.prototype.filter
+  // with adding support of @@species
+  _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 }, {
+    filter: function filter(callbackfn /* , thisArg */) {
+      return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
+    }
+  });
+
+  /**
+   * Set tooltip left so it doesn't go off the right side of the window
+   *
+   * @return boolean true, if tooltipLayerStyleLeft is ok.  false, otherwise.
+   */
+  function checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer) {
+    if (targetOffset.left + tooltipLayerStyleLeft + tooltipOffset.width > windowSize.width) {
+      // off the right side of the window
+      tooltipLayer.style.left = "".concat(windowSize.width - tooltipOffset.width - targetOffset.left, "px");
+      return false;
+    }
+
+    tooltipLayer.style.left = "".concat(tooltipLayerStyleLeft, "px");
+    return true;
+  }
+
+  /**
+   * Set tooltip right so it doesn't go off the left side of the window
+   *
+   * @return boolean true, if tooltipLayerStyleRight is ok.  false, otherwise.
+   */
+  function checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer) {
+    if (targetOffset.left + targetOffset.width - tooltipLayerStyleRight - tooltipOffset.width < 0) {
+      // off the left side of the window
+      tooltipLayer.style.left = "".concat(-targetOffset.left, "px");
+      return false;
+    }
+
+    tooltipLayer.style.right = "".concat(tooltipLayerStyleRight, "px");
+    return true;
+  }
+
+  var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('splice');
+
+  var max = Math.max;
+  var min = Math.min;
+  var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
+  var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';
+
+  // `Array.prototype.splice` method
+  // https://tc39.es/ecma262/#sec-array.prototype.splice
+  // with adding support of @@species
+  _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT }, {
+    splice: function splice(start, deleteCount /* , ...items */) {
+      var O = toObject(this);
+      var len = toLength(O.length);
+      var actualStart = toAbsoluteIndex(start, len);
+      var argumentsLength = arguments.length;
+      var insertCount, actualDeleteCount, A, k, from, to;
+      if (argumentsLength === 0) {
+        insertCount = actualDeleteCount = 0;
+      } else if (argumentsLength === 1) {
+        insertCount = 0;
+        actualDeleteCount = len - actualStart;
+      } else {
+        insertCount = argumentsLength - 2;
+        actualDeleteCount = min(max(toInteger(deleteCount), 0), len - actualStart);
+      }
+      if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER) {
+        throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
+      }
+      A = arraySpeciesCreate(O, actualDeleteCount);
+      for (k = 0; k < actualDeleteCount; k++) {
+        from = actualStart + k;
+        if (from in O) createProperty(A, k, O[from]);
+      }
+      A.length = actualDeleteCount;
+      if (insertCount < actualDeleteCount) {
+        for (k = actualStart; k < len - actualDeleteCount; k++) {
+          from = k + actualDeleteCount;
+          to = k + insertCount;
+          if (from in O) O[to] = O[from];
+          else delete O[to];
+        }
+        for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
+      } else if (insertCount > actualDeleteCount) {
+        for (k = len - actualDeleteCount; k > actualStart; k--) {
+          from = k + actualDeleteCount - 1;
+          to = k + insertCount - 1;
+          if (from in O) O[to] = O[from];
+          else delete O[to];
+        }
+      }
+      for (k = 0; k < insertCount; k++) {
+        O[k + actualStart] = arguments[k + 2];
+      }
+      O.length = len - actualDeleteCount + insertCount;
+      return A;
+    }
+  });
+
+  /**
+   * Remove an entry from a string array if it's there, does nothing if it isn't there.
+   *
+   * @param {Array} stringArray
+   * @param {String} stringToRemove
+   */
+  function removeEntry(stringArray, stringToRemove) {
+    if (stringArray.includes(stringToRemove)) {
+      stringArray.splice(stringArray.indexOf(stringToRemove), 1);
+    }
+  }
+
+  /**
+   * auto-determine alignment
+   * @param {Integer}  offsetLeft
+   * @param {Integer}  tooltipWidth
+   * @param {Object}   windowSize
+   * @param {String}   desiredAlignment
+   * @return {String}  calculatedAlignment
+   */
+
+  function _determineAutoAlignment(offsetLeft, tooltipWidth, _ref, desiredAlignment) {
+    var width = _ref.width;
+    var halfTooltipWidth = tooltipWidth / 2;
+    var winWidth = Math.min(width, window.screen.width);
+    var possibleAlignments = ["-left-aligned", "-middle-aligned", "-right-aligned"];
+    var calculatedAlignment = ""; // valid left must be at least a tooltipWidth
+    // away from right side
+
+    if (winWidth - offsetLeft < tooltipWidth) {
+      removeEntry(possibleAlignments, "-left-aligned");
+    } // valid middle must be at least half
+    // width away from both sides
+
+
+    if (offsetLeft < halfTooltipWidth || winWidth - offsetLeft < halfTooltipWidth) {
+      removeEntry(possibleAlignments, "-middle-aligned");
+    } // valid right must be at least a tooltipWidth
+    // width away from left side
+
+
+    if (offsetLeft < tooltipWidth) {
+      removeEntry(possibleAlignments, "-right-aligned");
+    }
+
+    if (possibleAlignments.length) {
+      if (possibleAlignments.includes(desiredAlignment)) {
+        // the desired alignment is valid
+        calculatedAlignment = desiredAlignment;
+      } else {
+        // pick the first valid position, in order
+        calculatedAlignment = possibleAlignments[0];
+      }
+    } else {
+      // if screen width is too small
+      // for ANY alignment, middle is
+      // probably the best for visibility
+      calculatedAlignment = "-middle-aligned";
+    }
+
+    return calculatedAlignment;
+  }
+  /**
+   * Determines the position of the tooltip based on the position precedence and availability
+   * of screen space.
+   *
+   * @param {Object}    targetElement
+   * @param {Object}    tooltipLayer
+   * @param {String}    desiredTooltipPosition
+   * @return {String}   calculatedPosition
+   */
+
+
+  function _determineAutoPosition(targetElement, tooltipLayer, desiredTooltipPosition) {
+    // Take a clone of position precedence. These will be the available
+    var possiblePositions = this._options.positionPrecedence.slice();
+
+    var windowSize = getWinSize();
+    var tooltipHeight = getOffset(tooltipLayer).height + 10;
+    var tooltipWidth = getOffset(tooltipLayer).width + 20;
+    var targetElementRect = targetElement.getBoundingClientRect(); // If we check all the possible areas, and there are no valid places for the tooltip, the element
+    // must take up most of the screen real estate. Show the tooltip floating in the middle of the screen.
+
+    var calculatedPosition = "floating";
+    /*
+     * auto determine position
+     */
+    // Check for space below
+
+    if (targetElementRect.bottom + tooltipHeight > windowSize.height) {
+      removeEntry(possiblePositions, "bottom");
+    } // Check for space above
+
+
+    if (targetElementRect.top - tooltipHeight < 0) {
+      removeEntry(possiblePositions, "top");
+    } // Check for space to the right
+
+
+    if (targetElementRect.right + tooltipWidth > windowSize.width) {
+      removeEntry(possiblePositions, "right");
+    } // Check for space to the left
+
+
+    if (targetElementRect.left - tooltipWidth < 0) {
+      removeEntry(possiblePositions, "left");
+    } // @var {String}  ex: 'right-aligned'
+
+
+    var desiredAlignment = function (pos) {
+      var hyphenIndex = pos.indexOf("-");
+
+      if (hyphenIndex !== -1) {
+        // has alignment
+        return pos.substr(hyphenIndex);
+      }
+
+      return "";
+    }(desiredTooltipPosition || ""); // strip alignment from position
+
+
+    if (desiredTooltipPosition) {
+      // ex: "bottom-right-aligned"
+      // should return 'bottom'
+      desiredTooltipPosition = desiredTooltipPosition.split("-")[0];
+    }
+
+    if (possiblePositions.length) {
+      if (possiblePositions.includes(desiredTooltipPosition)) {
+        // If the requested position is in the list, choose that
+        calculatedPosition = desiredTooltipPosition;
+      } else {
+        // Pick the first valid position, in order
+        calculatedPosition = possiblePositions[0];
+      }
+    } // only top and bottom positions have optional alignments
+
+
+    if (["top", "bottom"].includes(calculatedPosition)) {
+      calculatedPosition += _determineAutoAlignment(targetElementRect.left, tooltipWidth, windowSize, desiredAlignment);
+    }
+
+    return calculatedPosition;
+  }
+  /**
+   * Render tooltip box in the page
+   *
+   * @api private
+   * @method placeTooltip
+   * @param {HTMLElement} targetElement
+   * @param {HTMLElement} tooltipLayer
+   * @param {HTMLElement} arrowLayer
+   * @param {Boolean} hintMode
+   */
+
+
+  function placeTooltip(targetElement, tooltipLayer, arrowLayer, hintMode) {
+    var tooltipCssClass = "";
+    var currentStepObj;
+    var tooltipOffset;
+    var targetOffset;
+    var windowSize;
+    var currentTooltipPosition;
+    hintMode = hintMode || false; //reset the old style
+
+    tooltipLayer.style.top = null;
+    tooltipLayer.style.right = null;
+    tooltipLayer.style.bottom = null;
+    tooltipLayer.style.left = null;
+    tooltipLayer.style.marginLeft = null;
+    tooltipLayer.style.marginTop = null;
+    arrowLayer.style.display = "inherit"; //prevent error when `this._currentStep` is undefined
+
+    if (!this._introItems[this._currentStep]) return; //if we have a custom css class for each step
+
+    currentStepObj = this._introItems[this._currentStep];
+
+    if (typeof currentStepObj.tooltipClass === "string") {
+      tooltipCssClass = currentStepObj.tooltipClass;
+    } else {
+      tooltipCssClass = this._options.tooltipClass;
+    }
+
+    tooltipLayer.className = ["introjs-tooltip", tooltipCssClass].filter(Boolean).join(" ");
+    tooltipLayer.setAttribute("role", "dialog");
+    currentTooltipPosition = this._introItems[this._currentStep].position; // Floating is always valid, no point in calculating
+
+    if (currentTooltipPosition !== "floating" && this._options.autoPosition) {
+      currentTooltipPosition = _determineAutoPosition.call(this, targetElement, tooltipLayer, currentTooltipPosition);
+    }
+
+    var tooltipLayerStyleLeft;
+    targetOffset = getOffset(targetElement);
+    tooltipOffset = getOffset(tooltipLayer);
+    windowSize = getWinSize();
+    addClass(tooltipLayer, "introjs-".concat(currentTooltipPosition));
+
+    switch (currentTooltipPosition) {
+      case "top-right-aligned":
+        arrowLayer.className = "introjs-arrow bottom-right";
+        var tooltipLayerStyleRight = 0;
+        checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer);
+        tooltipLayer.style.bottom = "".concat(targetOffset.height + 20, "px");
+        break;
+
+      case "top-middle-aligned":
+        arrowLayer.className = "introjs-arrow bottom-middle";
+        var tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2; // a fix for middle aligned hints
+
+        if (hintMode) {
+          tooltipLayerStyleLeftRight += 5;
+        }
+
+        if (checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) {
+          tooltipLayer.style.right = null;
+          checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer);
+        }
+
+        tooltipLayer.style.bottom = "".concat(targetOffset.height + 20, "px");
+        break;
+
+      case "top-left-aligned": // top-left-aligned is the same as the default top
+
+      case "top":
+        arrowLayer.className = "introjs-arrow bottom";
+        tooltipLayerStyleLeft = hintMode ? 0 : 15;
+        checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer);
+        tooltipLayer.style.bottom = "".concat(targetOffset.height + 20, "px");
+        break;
+
+      case "right":
+        tooltipLayer.style.left = "".concat(targetOffset.width + 20, "px");
+
+        if (targetOffset.top + tooltipOffset.height > windowSize.height) {
+          // In this case, right would have fallen below the bottom of the screen.
+          // Modify so that the bottom of the tooltip connects with the target
+          arrowLayer.className = "introjs-arrow left-bottom";
+          tooltipLayer.style.top = "-".concat(tooltipOffset.height - targetOffset.height - 20, "px");
+        } else {
+          arrowLayer.className = "introjs-arrow left";
+        }
+
+        break;
+
+      case "left":
+        if (!hintMode && this._options.showStepNumbers === true) {
+          tooltipLayer.style.top = "15px";
+        }
+
+        if (targetOffset.top + tooltipOffset.height > windowSize.height) {
+          // In this case, left would have fallen below the bottom of the screen.
+          // Modify so that the bottom of the tooltip connects with the target
+          tooltipLayer.style.top = "-".concat(tooltipOffset.height - targetOffset.height - 20, "px");
+          arrowLayer.className = "introjs-arrow right-bottom";
+        } else {
+          arrowLayer.className = "introjs-arrow right";
+        }
+
+        tooltipLayer.style.right = "".concat(targetOffset.width + 20, "px");
+        break;
+
+      case "floating":
+        arrowLayer.style.display = "none"; //we have to adjust the top and left of layer manually for intro items without element
+
+        tooltipLayer.style.left = "50%";
+        tooltipLayer.style.top = "50%";
+        tooltipLayer.style.marginLeft = "-".concat(tooltipOffset.width / 2, "px");
+        tooltipLayer.style.marginTop = "-".concat(tooltipOffset.height / 2, "px");
+        break;
+
+      case "bottom-right-aligned":
+        arrowLayer.className = "introjs-arrow top-right";
+        tooltipLayerStyleRight = 0;
+        checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer);
+        tooltipLayer.style.top = "".concat(targetOffset.height + 20, "px");
+        break;
+
+      case "bottom-middle-aligned":
+        arrowLayer.className = "introjs-arrow top-middle";
+        tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2; // a fix for middle aligned hints
+
+        if (hintMode) {
+          tooltipLayerStyleLeftRight += 5;
+        }
+
+        if (checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) {
+          tooltipLayer.style.right = null;
+          checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer);
+        }
+
+        tooltipLayer.style.top = "".concat(targetOffset.height + 20, "px");
+        break;
+      // case 'bottom-left-aligned':
+      // Bottom-left-aligned is the same as the default bottom
+      // case 'bottom':
+      // Bottom going to follow the default behavior
+
+      default:
+        arrowLayer.className = "introjs-arrow top";
+        tooltipLayerStyleLeft = 0;
+        checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer);
+        tooltipLayer.style.top = "".concat(targetOffset.height + 20, "px");
+    }
+  }
+
+  /**
+   * To remove all show element(s)
+   *
+   * @api private
+   * @method _removeShowElement
+   */
+
+  function removeShowElement() {
+    var elms = document.querySelectorAll(".introjs-showElement");
+    forEach(elms, function (elm) {
+      removeClass(elm, /introjs-[a-zA-Z]+/g);
+    });
+  }
+
+  function _createElement(tagname, attrs) {
+    var element = document.createElement(tagname);
+    attrs = attrs || {}; // regex for matching attributes that need to be set with setAttribute
+
+    var setAttRegex = /^(?:role|data-|aria-)/;
+
+    for (var k in attrs) {
+      var v = attrs[k];
+
+      if (k === "style") {
+        setStyle(element, v);
+      } else if (k.match(setAttRegex)) {
+        element.setAttribute(k, v);
+      } else {
+        element[k] = v;
+      }
+    }
+
+    return element;
+  }
+
+  /**
+   * Appends `element` to `parentElement`
+   *
+   * @param {Element} parentElement
+   * @param {Element} element
+   * @param {Boolean} [animate=false]
+   */
+
+  function appendChild(parentElement, element, animate) {
+    if (animate) {
+      var existingOpacity = element.style.opacity || "1";
+      setStyle(element, {
+        opacity: "0"
+      });
+      window.setTimeout(function () {
+        setStyle(element, {
+          opacity: existingOpacity
+        });
+      }, 10);
+    }
+
+    parentElement.appendChild(element);
   }
 
   /**
@@ -2288,93 +2825,1763 @@
    * @method _getProgress
    * @returns current progress percentage
    */
+
   function _getProgress() {
     // Steps are 0 indexed
-    var currentStep = parseInt((this._currentStep + 1), 10);
-    return ((currentStep / this._introItems.length) * 100);
+    var currentStep = parseInt(this._currentStep + 1, 10);
+    return currentStep / this._introItems.length * 100;
+  }
+  /**
+   * Add disableinteraction layer and adjust the size and position of the layer
+   *
+   * @api private
+   * @method _disableInteraction
+   */
+
+
+  function _disableInteraction() {
+    var disableInteractionLayer = document.querySelector(".introjs-disableInteraction");
+
+    if (disableInteractionLayer === null) {
+      disableInteractionLayer = _createElement("div", {
+        className: "introjs-disableInteraction"
+      });
+
+      this._targetElement.appendChild(disableInteractionLayer);
+    }
+
+    setHelperLayerPosition.call(this, disableInteractionLayer);
+  }
+  /**
+   * Creates the bullets layer
+   * @returns HTMLElement
+   * @private
+   */
+
+
+  function _createBullets(targetElement) {
+    var self = this;
+    var bulletsLayer = _createElement("div", {
+      className: "introjs-bullets"
+    });
+
+    if (this._options.showBullets === false) {
+      bulletsLayer.style.display = "none";
+    }
+
+    var ulContainer = _createElement("ul");
+    ulContainer.setAttribute("role", "tablist");
+
+    var anchorClick = function anchorClick() {
+      self.goToStep(this.getAttribute("data-stepnumber"));
+    };
+
+    forEach(this._introItems, function (_ref, i) {
+      var step = _ref.step;
+      var innerLi = _createElement("li");
+      var anchorLink = _createElement("a");
+      innerLi.setAttribute("role", "presentation");
+      anchorLink.setAttribute("role", "tab");
+      anchorLink.onclick = anchorClick;
+
+      if (i === targetElement.step - 1) {
+        anchorLink.className = "active";
+      }
+
+      setAnchorAsButton(anchorLink);
+      anchorLink.innerHTML = "&nbsp;";
+      anchorLink.setAttribute("data-stepnumber", step);
+      innerLi.appendChild(anchorLink);
+      ulContainer.appendChild(innerLi);
+    });
+    bulletsLayer.appendChild(ulContainer);
+    return bulletsLayer;
+  }
+  /**
+   * Deletes and recreates the bullets layer
+   * @param oldReferenceLayer
+   * @param targetElement
+   * @private
+   */
+
+
+  function _recreateBullets(oldReferenceLayer, targetElement) {
+    if (this._options.showBullets) {
+      var existing = document.querySelector(".introjs-bullets");
+      existing.parentNode.replaceChild(_createBullets.call(this, targetElement), existing);
+    }
+  }
+  /**
+   * Updates the bullets
+   *
+   * @param oldReferenceLayer
+   * @param targetElement
+   */
+
+  function _updateBullets(oldReferenceLayer, targetElement) {
+    if (this._options.showBullets) {
+      oldReferenceLayer.querySelector(".introjs-bullets li > a.active").className = "";
+      oldReferenceLayer.querySelector(".introjs-bullets li > a[data-stepnumber=\"".concat(targetElement.step, "\"]")).className = "active";
+    }
+  }
+  /**
+   * Creates the progress-bar layer and elements
+   * @returns {*}
+   * @private
+   */
+
+
+  function _createProgressBar() {
+    var progressLayer = _createElement("div");
+    progressLayer.className = "introjs-progress";
+
+    if (this._options.showProgress === false) {
+      progressLayer.style.display = "none";
+    }
+
+    var progressBar = _createElement("div", {
+      className: "introjs-progressbar"
+    });
+
+    if (this._options.progressBarAdditionalClass) {
+      progressBar.className += " " + this._options.progressBarAdditionalClass;
+    }
+
+    progressBar.setAttribute("role", "progress");
+    progressBar.setAttribute("aria-valuemin", 0);
+    progressBar.setAttribute("aria-valuemax", 100);
+    progressBar.setAttribute("aria-valuenow", _getProgress.call(this));
+    progressBar.style.cssText = "width:".concat(_getProgress.call(this), "%;");
+    progressLayer.appendChild(progressBar);
+    return progressLayer;
+  }
+  /**
+   * Updates an existing progress bar variables
+   * @param oldReferenceLayer
+   * @private
+   */
+
+
+  function _updateProgressBar(oldReferenceLayer) {
+    oldReferenceLayer.querySelector(".introjs-progress .introjs-progressbar").style.cssText = "width:".concat(_getProgress.call(this), "%;");
+    oldReferenceLayer.querySelector(".introjs-progress .introjs-progressbar").setAttribute("aria-valuenow", _getProgress.call(this));
+  }
+  /**
+   * Show an element on the page
+   *
+   * @api private
+   * @method _showElement
+   * @param {Object} targetElement
+   */
+
+  function _showElement(targetElement) {
+    var _this = this;
+
+    if (typeof this._introChangeCallback !== "undefined") {
+      this._introChangeCallback.call(this, targetElement.element);
+    }
+
+    var self = this;
+    var oldHelperLayer = document.querySelector(".introjs-helperLayer");
+    var oldReferenceLayer = document.querySelector(".introjs-tooltipReferenceLayer");
+    var highlightClass = "introjs-helperLayer";
+    var nextTooltipButton;
+    var prevTooltipButton;
+    var skipTooltipButton; //check for a current step highlight class
+
+    if (typeof targetElement.highlightClass === "string") {
+      highlightClass += " ".concat(targetElement.highlightClass);
+    } //check for options highlight class
+
+
+    if (typeof this._options.highlightClass === "string") {
+      highlightClass += " ".concat(this._options.highlightClass);
+    }
+
+    if (oldHelperLayer !== null && oldReferenceLayer !== null) {
+      var oldHelperNumberLayer = oldReferenceLayer.querySelector(".introjs-helperNumberLayer");
+      var oldtooltipLayer = oldReferenceLayer.querySelector(".introjs-tooltiptext");
+      var oldTooltipTitleLayer = oldReferenceLayer.querySelector(".introjs-tooltip-title");
+      var oldArrowLayer = oldReferenceLayer.querySelector(".introjs-arrow");
+      var oldtooltipContainer = oldReferenceLayer.querySelector(".introjs-tooltip");
+      skipTooltipButton = oldReferenceLayer.querySelector(".introjs-skipbutton");
+      prevTooltipButton = oldReferenceLayer.querySelector(".introjs-prevbutton");
+      nextTooltipButton = oldReferenceLayer.querySelector(".introjs-nextbutton"); //update or reset the helper highlight class
+
+      oldHelperLayer.className = highlightClass; //hide the tooltip
+
+      oldtooltipContainer.style.opacity = 0;
+      oldtooltipContainer.style.display = "none"; // if the target element is within a scrollable element
+
+      scrollParentToElement.call(self, targetElement); // set new position to helper layer
+
+      setHelperLayerPosition.call(self, oldHelperLayer);
+      setHelperLayerPosition.call(self, oldReferenceLayer); //remove old classes if the element still exist
+
+      removeShowElement(); //we should wait until the CSS3 transition is competed (it's 0.3 sec) to prevent incorrect `height` and `width` calculation
+
+      if (self._lastShowElementTimer) {
+        window.clearTimeout(self._lastShowElementTimer);
+      }
+
+      self._lastShowElementTimer = window.setTimeout(function () {
+        // set current step to the label
+        if (oldHelperNumberLayer !== null) {
+          oldHelperNumberLayer.innerHTML = "".concat(targetElement.step, " of ").concat(_this._introItems.length);
+        } // set current tooltip text
+
+
+        oldtooltipLayer.innerHTML = targetElement.intro; // set current tooltip title
+
+        oldTooltipTitleLayer.innerHTML = targetElement.title; //set the tooltip position
+
+        oldtooltipContainer.style.display = "block";
+        placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer); //change active bullet
+
+        _updateBullets.call(self, oldReferenceLayer, targetElement);
+
+        _updateProgressBar.call(self, oldReferenceLayer); //show the tooltip
+
+
+        oldtooltipContainer.style.opacity = 1; //reset button focus
+
+        if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null && /introjs-donebutton/gi.test(nextTooltipButton.className)) {
+          // skip button is now "done" button
+          nextTooltipButton.focus();
+        } else if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
+          //still in the tour, focus on next
+          nextTooltipButton.focus();
+        } // change the scroll of the window, if needed
+
+
+        scrollTo.call(self, targetElement.scrollTo, targetElement, oldtooltipLayer);
+      }, 350); // end of old element if-else condition
+    } else {
+      var helperLayer = _createElement("div", {
+        className: highlightClass
+      });
+      var referenceLayer = _createElement("div", {
+        className: "introjs-tooltipReferenceLayer"
+      });
+      var arrowLayer = _createElement("div", {
+        className: "introjs-arrow"
+      });
+      var tooltipLayer = _createElement("div", {
+        className: "introjs-tooltip"
+      });
+      var tooltipTextLayer = _createElement("div", {
+        className: "introjs-tooltiptext"
+      });
+      var tooltipHeaderLayer = _createElement("div", {
+        className: "introjs-tooltip-header"
+      });
+      var tooltipTitleLayer = _createElement("h1", {
+        className: "introjs-tooltip-title"
+      });
+      var buttonsLayer = _createElement("div");
+      setStyle(helperLayer, {
+        "box-shadow": "0 0 1px 2px rgba(33, 33, 33, 0.8), rgba(33, 33, 33, ".concat(self._options.overlayOpacity.toString(), ") 0 0 0 5000px")
+      }); // target is within a scrollable element
+
+      scrollParentToElement.call(self, targetElement); //set new position to helper layer
+
+      setHelperLayerPosition.call(self, helperLayer);
+      setHelperLayerPosition.call(self, referenceLayer); //add helper layer to target element
+
+      appendChild(this._targetElement, helperLayer, true);
+      appendChild(this._targetElement, referenceLayer);
+      tooltipTextLayer.innerHTML = targetElement.intro;
+      tooltipTitleLayer.innerHTML = targetElement.title;
+      buttonsLayer.className = "introjs-tooltipbuttons";
+
+      if (this._options.showButtons === false) {
+        buttonsLayer.style.display = "none";
+      }
+
+      tooltipHeaderLayer.appendChild(tooltipTitleLayer);
+      tooltipLayer.appendChild(tooltipHeaderLayer);
+      tooltipLayer.appendChild(tooltipTextLayer);
+      tooltipLayer.appendChild(_createBullets.call(this, targetElement));
+      tooltipLayer.appendChild(_createProgressBar.call(this)); // add helper layer number
+
+      var helperNumberLayer = _createElement("div");
+
+      if (this._options.showStepNumbers === true) {
+        helperNumberLayer.className = "introjs-helperNumberLayer";
+        helperNumberLayer.innerHTML = "".concat(targetElement.step, " of ").concat(this._introItems.length);
+        tooltipLayer.appendChild(helperNumberLayer);
+      }
+
+      tooltipLayer.appendChild(arrowLayer);
+      referenceLayer.appendChild(tooltipLayer); //next button
+
+      nextTooltipButton = _createElement("a");
+
+      nextTooltipButton.onclick = function () {
+        if (self._introItems.length - 1 !== self._currentStep) {
+          nextStep.call(self);
+        } else if (/introjs-donebutton/gi.test(nextTooltipButton.className)) {
+          if (typeof self._introCompleteCallback === "function") {
+            self._introCompleteCallback.call(self);
+          }
+
+          exitIntro.call(self, self._targetElement);
+        }
+      };
+
+      setAnchorAsButton(nextTooltipButton);
+      nextTooltipButton.innerHTML = this._options.nextLabel; //previous button
+
+      prevTooltipButton = _createElement("a");
+
+      prevTooltipButton.onclick = function () {
+        if (self._currentStep !== 0) {
+          previousStep.call(self);
+        }
+      };
+
+      setAnchorAsButton(prevTooltipButton);
+      prevTooltipButton.innerHTML = this._options.prevLabel; //skip button
+
+      skipTooltipButton = _createElement("a", {
+        className: "introjs-skipbutton"
+      });
+      setAnchorAsButton(skipTooltipButton);
+      skipTooltipButton.innerHTML = this._options.skipLabel;
+
+      skipTooltipButton.onclick = function () {
+        if (self._introItems.length - 1 === self._currentStep && typeof self._introCompleteCallback === "function") {
+          self._introCompleteCallback.call(self);
+        }
+
+        if (typeof self._introSkipCallback === "function") {
+          self._introSkipCallback.call(self);
+        }
+
+        exitIntro.call(self, self._targetElement);
+      };
+
+      tooltipHeaderLayer.appendChild(skipTooltipButton); //in order to prevent displaying previous button always
+
+      if (this._introItems.length > 1) {
+        buttonsLayer.appendChild(prevTooltipButton);
+      } // we always need the next button because this
+      // button changes to "Done" in the last step of the tour
+
+
+      buttonsLayer.appendChild(nextTooltipButton);
+      tooltipLayer.appendChild(buttonsLayer); //set proper position
+
+      placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer); // change the scroll of the window, if needed
+
+      scrollTo.call(this, targetElement.scrollTo, targetElement, tooltipLayer); //end of new element if-else condition
+    } // removing previous disable interaction layer
+
+
+    var disableInteractionLayer = self._targetElement.querySelector(".introjs-disableInteraction");
+
+    if (disableInteractionLayer) {
+      disableInteractionLayer.parentNode.removeChild(disableInteractionLayer);
+    } //disable interaction
+
+
+    if (targetElement.disableInteraction) {
+      _disableInteraction.call(self);
+    } // when it's the first step of tour
+
+
+    if (this._currentStep === 0 && this._introItems.length > 1) {
+      if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
+        nextTooltipButton.className = "".concat(this._options.buttonClass, " introjs-nextbutton");
+        nextTooltipButton.innerHTML = this._options.nextLabel;
+      }
+
+      if (this._options.hidePrev === true) {
+        if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
+          prevTooltipButton.className = "".concat(this._options.buttonClass, " introjs-prevbutton introjs-hidden");
+        }
+
+        if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
+          addClass(nextTooltipButton, "introjs-fullbutton");
+        }
+      } else {
+        if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
+          prevTooltipButton.className = "".concat(this._options.buttonClass, " introjs-prevbutton introjs-disabled");
+        }
+      }
+    } else if (this._introItems.length - 1 === this._currentStep || this._introItems.length === 1) {
+      // last step of tour
+      if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
+        prevTooltipButton.className = "".concat(this._options.buttonClass, " introjs-prevbutton");
+      }
+
+      if (this._options.hideNext === true) {
+        if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
+          nextTooltipButton.className = "".concat(this._options.buttonClass, " introjs-nextbutton introjs-hidden");
+        }
+
+        if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
+          addClass(prevTooltipButton, "introjs-fullbutton");
+        }
+      } else {
+        if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
+          if (this._options.nextToDone === true) {
+            nextTooltipButton.innerHTML = this._options.doneLabel;
+            addClass(nextTooltipButton, "".concat(this._options.buttonClass, " introjs-nextbutton introjs-donebutton"));
+          } else {
+            nextTooltipButton.className = "".concat(this._options.buttonClass, " introjs-nextbutton introjs-disabled");
+          }
+        }
+      }
+    } else {
+      // steps between start and end
+      if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
+        prevTooltipButton.className = "".concat(this._options.buttonClass, " introjs-prevbutton");
+      }
+
+      if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
+        nextTooltipButton.className = "".concat(this._options.buttonClass, " introjs-nextbutton");
+        nextTooltipButton.innerHTML = this._options.nextLabel;
+      }
+    }
+
+    if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) {
+      prevTooltipButton.setAttribute("role", "button");
+    }
+
+    if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
+      nextTooltipButton.setAttribute("role", "button");
+    }
+
+    if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) {
+      skipTooltipButton.setAttribute("role", "button");
+    } //Set focus on "next" button, so that hitting Enter always moves you onto the next step
+
+
+    if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) {
+      nextTooltipButton.focus();
+    }
+
+    setShowElement(targetElement);
+
+    if (typeof this._introAfterChangeCallback !== "undefined") {
+      this._introAfterChangeCallback.call(this, targetElement.element);
+    }
   }
 
   /**
-   * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
-   * via: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically
+   * Go to specific step of introduction
    *
-   * @param obj1
-   * @param obj2
-   * @returns obj3 a new object based on obj1 and obj2
+   * @api private
+   * @method _goToStep
    */
-  function _mergeOptions(obj1,obj2) {
-    var obj3 = {},
-      attrname;
-    for (attrname in obj1) { obj3[attrname] = obj1[attrname]; }
-    for (attrname in obj2) { obj3[attrname] = obj2[attrname]; }
-    return obj3;
+
+  function goToStep(step) {
+    //because steps starts with zero
+    this._currentStep = step - 2;
+
+    if (typeof this._introItems !== "undefined") {
+      nextStep.call(this);
+    }
+  }
+  /**
+   * Go to the specific step of introduction with the explicit [data-step] number
+   *
+   * @api private
+   * @method _goToStepNumber
+   */
+
+  function goToStepNumber(step) {
+    this._currentStepNumber = step;
+
+    if (typeof this._introItems !== "undefined") {
+      nextStep.call(this);
+    }
+  }
+  /**
+   * Go to next step on intro
+   *
+   * @api private
+   * @method _nextStep
+   */
+
+  function nextStep() {
+    var _this = this;
+
+    this._direction = "forward";
+
+    if (typeof this._currentStepNumber !== "undefined") {
+      forEach(this._introItems, function (_ref, i) {
+        var step = _ref.step;
+
+        if (step === _this._currentStepNumber) {
+          _this._currentStep = i - 1;
+          _this._currentStepNumber = undefined;
+        }
+      });
+    }
+
+    if (typeof this._currentStep === "undefined") {
+      this._currentStep = 0;
+    } else {
+      ++this._currentStep;
+    }
+
+    var nextStep = this._introItems[this._currentStep];
+    var continueStep = true;
+
+    if (typeof this._introBeforeChangeCallback !== "undefined") {
+      continueStep = this._introBeforeChangeCallback.call(this, nextStep && nextStep.element);
+    } // if `onbeforechange` returned `false`, stop displaying the element
+
+
+    if (continueStep === false) {
+      --this._currentStep;
+      return false;
+    }
+
+    if (this._introItems.length <= this._currentStep) {
+      //end of the intro
+      //check if any callback is defined
+      if (typeof this._introCompleteCallback === "function") {
+        this._introCompleteCallback.call(this);
+      }
+
+      exitIntro.call(this, this._targetElement);
+      return;
+    }
+
+    _showElement.call(this, nextStep);
+  }
+  /**
+   * Go to previous step on intro
+   *
+   * @api private
+   * @method _previousStep
+   */
+
+  function previousStep() {
+    this._direction = "backward";
+
+    if (this._currentStep === 0) {
+      return false;
+    }
+
+    --this._currentStep;
+    var nextStep = this._introItems[this._currentStep];
+    var continueStep = true;
+
+    if (typeof this._introBeforeChangeCallback !== "undefined") {
+      continueStep = this._introBeforeChangeCallback.call(this, nextStep && nextStep.element);
+    } // if `onbeforechange` returned `false`, stop displaying the element
+
+
+    if (continueStep === false) {
+      ++this._currentStep;
+      return false;
+    }
+
+    _showElement.call(this, nextStep);
+  }
+  /**
+   * Returns the current step of the intro
+   *
+   * @returns {number | boolean}
+   */
+
+  function currentStep() {
+    return this._currentStep;
   }
 
-  var introJs = function (targetElm) {
+  /**
+   * on keyCode:
+   * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
+   * This feature has been removed from the Web standards.
+   * Though some browsers may still support it, it is in
+   * the process of being dropped.
+   * Instead, you should use KeyboardEvent.code,
+   * if it's implemented.
+   *
+   * jQuery's approach is to test for
+   *   (1) e.which, then
+   *   (2) e.charCode, then
+   *   (3) e.keyCode
+   * https://github.com/jquery/jquery/blob/a6b0705294d336ae2f63f7276de0da1195495363/src/event.js#L638
+   *
+   * @param type var
+   * @return type
+   */
+
+  function onKeyDown(e) {
+    var code = e.code === undefined ? e.which : e.code; // if e.which is null
+
+    if (code === null) {
+      code = e.charCode === null ? e.keyCode : e.charCode;
+    }
+
+    if ((code === "Escape" || code === 27) && this._options.exitOnEsc === true) {
+      //escape key pressed, exit the intro
+      //check if exit callback is defined
+      exitIntro.call(this, this._targetElement);
+    } else if (code === "ArrowLeft" || code === 37) {
+      //left arrow
+      previousStep.call(this);
+    } else if (code === "ArrowRight" || code === 39) {
+      //right arrow
+      nextStep.call(this);
+    } else if (code === "Enter" || code === "NumpadEnter" || code === 13) {
+      //srcElement === ie
+      var target = e.target || e.srcElement;
+
+      if (target && target.className.match("introjs-prevbutton")) {
+        //user hit enter while focusing on previous button
+        previousStep.call(this);
+      } else if (target && target.className.match("introjs-skipbutton")) {
+        //user hit enter while focusing on skip button
+        if (this._introItems.length - 1 === this._currentStep && typeof this._introCompleteCallback === "function") {
+          this._introCompleteCallback.call(this);
+        }
+
+        exitIntro.call(this, this._targetElement);
+      } else if (target && target.getAttribute("data-stepnumber")) {
+        // user hit enter while focusing on step bullet
+        target.click();
+      } else {
+        //default behavior for responding to enter
+        nextStep.call(this);
+      } //prevent default behaviour on hitting Enter, to prevent steps being skipped in some browsers
+
+
+      if (e.preventDefault) {
+        e.preventDefault();
+      } else {
+        e.returnValue = false;
+      }
+    }
+  }
+
+  /*
+   * makes a copy of the object
+   * @api private
+   * @method _cloneObject
+   */
+  function cloneObject(object) {
+    if (object === null || _typeof(object) !== "object" || typeof object.nodeType !== "undefined") {
+      return object;
+    }
+
+    var temp = {};
+
+    for (var key in object) {
+      if (typeof window.jQuery !== "undefined" && object[key] instanceof window.jQuery) {
+        temp[key] = object[key];
+      } else {
+        temp[key] = cloneObject(object[key]);
+      }
+    }
+
+    return temp;
+  }
+
+  /**
+   * Get a queryselector within the hint wrapper
+   *
+   * @param {String} selector
+   * @return {NodeList|Array}
+   */
+
+  function hintQuerySelectorAll(selector) {
+    var hintsWrapper = document.querySelector(".introjs-hints");
+    return hintsWrapper ? hintsWrapper.querySelectorAll(selector) : [];
+  }
+  /**
+   * Hide a hint
+   *
+   * @api private
+   * @method hideHint
+   */
+
+  function hideHint(stepId) {
+    var hint = hintQuerySelectorAll(".introjs-hint[data-step=\"".concat(stepId, "\"]"))[0];
+    removeHintTooltip.call(this);
+
+    if (hint) {
+      addClass(hint, "introjs-hidehint");
+    } // call the callback function (if any)
+
+
+    if (typeof this._hintCloseCallback !== "undefined") {
+      this._hintCloseCallback.call(this, stepId);
+    }
+  }
+  /**
+   * Hide all hints
+   *
+   * @api private
+   * @method hideHints
+   */
+
+  function hideHints() {
+    var _this = this;
+
+    var hints = hintQuerySelectorAll(".introjs-hint");
+    forEach(hints, function (hint) {
+      hideHint.call(_this, hint.getAttribute("data-step"));
+    });
+  }
+  /**
+   * Show all hints
+   *
+   * @api private
+   * @method _showHints
+   */
+
+  function showHints() {
+    var _this2 = this;
+
+    var hints = hintQuerySelectorAll(".introjs-hint");
+
+    if (hints && hints.length) {
+      forEach(hints, function (hint) {
+        showHint.call(_this2, hint.getAttribute("data-step"));
+      });
+    } else {
+      populateHints.call(this, this._targetElement);
+    }
+  }
+  /**
+   * Show a hint
+   *
+   * @api private
+   * @method showHint
+   */
+
+  function showHint(stepId) {
+    var hint = hintQuerySelectorAll(".introjs-hint[data-step=\"".concat(stepId, "\"]"))[0];
+
+    if (hint) {
+      removeClass(hint, /introjs-hidehint/g);
+    }
+  }
+  /**
+   * Removes all hint elements on the page
+   * Useful when you want to destroy the elements and add them again (e.g. a modal or popup)
+   *
+   * @api private
+   * @method removeHints
+   */
+
+  function removeHints() {
+    var _this3 = this;
+
+    var hints = hintQuerySelectorAll(".introjs-hint");
+    forEach(hints, function (hint) {
+      removeHint.call(_this3, hint.getAttribute("data-step"));
+    });
+  }
+  /**
+   * Remove one single hint element from the page
+   * Useful when you want to destroy the element and add them again (e.g. a modal or popup)
+   * Use removeHints if you want to remove all elements.
+   *
+   * @api private
+   * @method removeHint
+   */
+
+  function removeHint(stepId) {
+    var hint = hintQuerySelectorAll(".introjs-hint[data-step=\"".concat(stepId, "\"]"))[0];
+
+    if (hint) {
+      hint.parentNode.removeChild(hint);
+    }
+  }
+  /**
+   * Add all available hints to the page
+   *
+   * @api private
+   * @method addHints
+   */
+
+  function addHints() {
+    var _this4 = this;
+
+    var self = this;
+    var hintsWrapper = document.querySelector(".introjs-hints");
+
+    if (hintsWrapper === null) {
+      hintsWrapper = _createElement("div", {
+        className: "introjs-hints"
+      });
+    }
+    /**
+     * Returns an event handler unique to the hint iteration
+     *
+     * @param {Integer} i
+     * @return {Function}
+     */
+
+
+    var getHintClick = function getHintClick(i) {
+      return function (e) {
+        var evt = e ? e : window.event;
+
+        if (evt.stopPropagation) {
+          evt.stopPropagation();
+        }
+
+        if (evt.cancelBubble !== null) {
+          evt.cancelBubble = true;
+        }
+
+        showHintDialog.call(self, i);
+      };
+    };
+
+    forEach(this._introItems, function (item, i) {
+      // avoid append a hint twice
+      if (document.querySelector(".introjs-hint[data-step=\"".concat(i, "\"]"))) {
+        return;
+      }
+
+      var hint = _createElement("a", {
+        className: "introjs-hint"
+      });
+      setAnchorAsButton(hint);
+      hint.onclick = getHintClick(i);
+
+      if (!item.hintAnimation) {
+        addClass(hint, "introjs-hint-no-anim");
+      } // hint's position should be fixed if the target element's position is fixed
+
+
+      if (isFixed(item.element)) {
+        addClass(hint, "introjs-fixedhint");
+      }
+
+      var hintDot = _createElement("div", {
+        className: "introjs-hint-dot"
+      });
+      var hintPulse = _createElement("div", {
+        className: "introjs-hint-pulse"
+      });
+      hint.appendChild(hintDot);
+      hint.appendChild(hintPulse);
+      hint.setAttribute("data-step", i); // we swap the hint element with target element
+      // because _setHelperLayerPosition uses `element` property
+
+      item.targetElement = item.element;
+      item.element = hint; // align the hint position
+
+      alignHintPosition.call(_this4, item.hintPosition, hint, item.targetElement);
+      hintsWrapper.appendChild(hint);
+    }); // adding the hints wrapper
+
+    document.body.appendChild(hintsWrapper); // call the callback function (if any)
+
+    if (typeof this._hintsAddedCallback !== "undefined") {
+      this._hintsAddedCallback.call(this);
+    }
+  }
+  /**
+   * Aligns hint position
+   *
+   * @api private
+   * @method alignHintPosition
+   * @param {String} position
+   * @param {Object} hint
+   * @param {Object} element
+   */
+
+  function alignHintPosition(position, _ref, element) {
+    var style = _ref.style;
+    // get/calculate offset of target element
+    var offset = getOffset.call(this, element);
+    var iconWidth = 20;
+    var iconHeight = 20; // align the hint element
+
+    switch (position) {
+      default:
+      case "top-left":
+        style.left = "".concat(offset.left, "px");
+        style.top = "".concat(offset.top, "px");
+        break;
+
+      case "top-right":
+        style.left = "".concat(offset.left + offset.width - iconWidth, "px");
+        style.top = "".concat(offset.top, "px");
+        break;
+
+      case "bottom-left":
+        style.left = "".concat(offset.left, "px");
+        style.top = "".concat(offset.top + offset.height - iconHeight, "px");
+        break;
+
+      case "bottom-right":
+        style.left = "".concat(offset.left + offset.width - iconWidth, "px");
+        style.top = "".concat(offset.top + offset.height - iconHeight, "px");
+        break;
+
+      case "middle-left":
+        style.left = "".concat(offset.left, "px");
+        style.top = "".concat(offset.top + (offset.height - iconHeight) / 2, "px");
+        break;
+
+      case "middle-right":
+        style.left = "".concat(offset.left + offset.width - iconWidth, "px");
+        style.top = "".concat(offset.top + (offset.height - iconHeight) / 2, "px");
+        break;
+
+      case "middle-middle":
+        style.left = "".concat(offset.left + (offset.width - iconWidth) / 2, "px");
+        style.top = "".concat(offset.top + (offset.height - iconHeight) / 2, "px");
+        break;
+
+      case "bottom-middle":
+        style.left = "".concat(offset.left + (offset.width - iconWidth) / 2, "px");
+        style.top = "".concat(offset.top + offset.height - iconHeight, "px");
+        break;
+
+      case "top-middle":
+        style.left = "".concat(offset.left + (offset.width - iconWidth) / 2, "px");
+        style.top = "".concat(offset.top, "px");
+        break;
+    }
+  }
+  /**
+   * Triggers when user clicks on the hint element
+   *
+   * @api private
+   * @method _showHintDialog
+   * @param {Number} stepId
+   */
+
+  function showHintDialog(stepId) {
+    var hintElement = document.querySelector(".introjs-hint[data-step=\"".concat(stepId, "\"]"));
+    var item = this._introItems[stepId]; // call the callback function (if any)
+
+    if (typeof this._hintClickCallback !== "undefined") {
+      this._hintClickCallback.call(this, hintElement, item, stepId);
+    } // remove all open tooltips
+
+
+    var removedStep = removeHintTooltip.call(this); // to toggle the tooltip
+
+    if (parseInt(removedStep, 10) === stepId) {
+      return;
+    }
+
+    var tooltipLayer = _createElement("div", {
+      className: "introjs-tooltip"
+    });
+    var tooltipTextLayer = _createElement("div");
+    var arrowLayer = _createElement("div");
+    var referenceLayer = _createElement("div");
+
+    tooltipLayer.onclick = function (e) {
+      //IE9 & Other Browsers
+      if (e.stopPropagation) {
+        e.stopPropagation();
+      } //IE8 and Lower
+      else {
+        e.cancelBubble = true;
+      }
+    };
+
+    tooltipTextLayer.className = "introjs-tooltiptext";
+    var tooltipWrapper = _createElement("p");
+    tooltipWrapper.innerHTML = item.hint;
+    var closeButton = _createElement("a");
+    closeButton.className = this._options.buttonClass;
+    closeButton.setAttribute("role", "button");
+    closeButton.innerHTML = this._options.hintButtonLabel;
+    closeButton.onclick = hideHint.bind(this, stepId);
+    tooltipTextLayer.appendChild(tooltipWrapper);
+    tooltipTextLayer.appendChild(closeButton);
+    arrowLayer.className = "introjs-arrow";
+    tooltipLayer.appendChild(arrowLayer);
+    tooltipLayer.appendChild(tooltipTextLayer); // set current step for _placeTooltip function
+
+    this._currentStep = hintElement.getAttribute("data-step"); // align reference layer position
+
+    referenceLayer.className = "introjs-tooltipReferenceLayer introjs-hintReference";
+    referenceLayer.setAttribute("data-step", hintElement.getAttribute("data-step"));
+    setHelperLayerPosition.call(this, referenceLayer);
+    referenceLayer.appendChild(tooltipLayer);
+    document.body.appendChild(referenceLayer); //set proper position
+
+    placeTooltip.call(this, hintElement, tooltipLayer, arrowLayer, true);
+  }
+  /**
+   * Removes open hint (tooltip hint)
+   *
+   * @api private
+   * @method _removeHintTooltip
+   */
+
+  function removeHintTooltip() {
+    var tooltip = document.querySelector(".introjs-hintReference");
+
+    if (tooltip) {
+      var step = tooltip.getAttribute("data-step");
+      tooltip.parentNode.removeChild(tooltip);
+      return step;
+    }
+  }
+  /**
+   * Start parsing hint items
+   *
+   * @api private
+   * @param {Object} targetElm
+   * @method _startHint
+   */
+
+  function populateHints(targetElm) {
+    var _this5 = this;
+
+    this._introItems = [];
+
+    if (this._options.hints) {
+      forEach(this._options.hints, function (hint) {
+        var currentItem = cloneObject(hint);
+
+        if (typeof currentItem.element === "string") {
+          //grab the element with given selector from the page
+          currentItem.element = document.querySelector(currentItem.element);
+        }
+
+        currentItem.hintPosition = currentItem.hintPosition || _this5._options.hintPosition;
+        currentItem.hintAnimation = currentItem.hintAnimation || _this5._options.hintAnimation;
+
+        if (currentItem.element !== null) {
+          _this5._introItems.push(currentItem);
+        }
+      });
+    } else {
+      var hints = targetElm.querySelectorAll("*[data-hint]");
+
+      if (!hints || !hints.length) {
+        return false;
+      } //first add intro items with data-step
+
+
+      forEach(hints, function (currentElement) {
+        // hint animation
+        var hintAnimation = currentElement.getAttribute("data-hintanimation");
+
+        if (hintAnimation) {
+          hintAnimation = hintAnimation === "true";
+        } else {
+          hintAnimation = _this5._options.hintAnimation;
+        }
+
+        _this5._introItems.push({
+          element: currentElement,
+          hint: currentElement.getAttribute("data-hint"),
+          hintPosition: currentElement.getAttribute("data-hintposition") || _this5._options.hintPosition,
+          hintAnimation: hintAnimation,
+          tooltipClass: currentElement.getAttribute("data-tooltipclass"),
+          position: currentElement.getAttribute("data-position") || _this5._options.tooltipPosition
+        });
+      });
+    }
+
+    addHints.call(this);
+    /*
+    todo:
+    these events should be removed at some point
+    */
+
+    DOMEvent.on(document, "click", removeHintTooltip, this, false);
+    DOMEvent.on(window, "resize", reAlignHints, this, true);
+  }
+  /**
+   * Re-aligns all hint elements
+   *
+   * @api private
+   * @method _reAlignHints
+   */
+
+  function reAlignHints() {
+    var _this6 = this;
+
+    forEach(this._introItems, function (_ref2) {
+      var targetElement = _ref2.targetElement,
+          hintPosition = _ref2.hintPosition,
+          element = _ref2.element;
+
+      if (typeof targetElement === "undefined") {
+        return;
+      }
+
+      alignHintPosition.call(_this6, hintPosition, element, targetElement);
+    });
+  }
+
+  // TODO: use something more complex like timsort?
+  var floor = Math.floor;
+
+  var mergeSort = function (array, comparefn) {
+    var length = array.length;
+    var middle = floor(length / 2);
+    return length < 8 ? insertionSort(array, comparefn) : merge(
+      mergeSort(array.slice(0, middle), comparefn),
+      mergeSort(array.slice(middle), comparefn),
+      comparefn
+    );
+  };
+
+  var insertionSort = function (array, comparefn) {
+    var length = array.length;
+    var i = 1;
+    var element, j;
+
+    while (i < length) {
+      j = i;
+      element = array[i];
+      while (j && comparefn(array[j - 1], element) > 0) {
+        array[j] = array[--j];
+      }
+      if (j !== i++) array[j] = element;
+    } return array;
+  };
+
+  var merge = function (left, right, comparefn) {
+    var llength = left.length;
+    var rlength = right.length;
+    var lindex = 0;
+    var rindex = 0;
+    var result = [];
+
+    while (lindex < llength || rindex < rlength) {
+      if (lindex < llength && rindex < rlength) {
+        result.push(comparefn(left[lindex], right[rindex]) <= 0 ? left[lindex++] : right[rindex++]);
+      } else {
+        result.push(lindex < llength ? left[lindex++] : right[rindex++]);
+      }
+    } return result;
+  };
+
+  var arraySort = mergeSort;
+
+  var firefox = engineUserAgent.match(/firefox\/(\d+)/i);
+
+  var engineFfVersion = !!firefox && +firefox[1];
+
+  var engineIsIeOrEdge = /MSIE|Trident/.test(engineUserAgent);
+
+  var webkit = engineUserAgent.match(/AppleWebKit\/(\d+)\./);
+
+  var engineWebkitVersion = !!webkit && +webkit[1];
+
+  var test = [];
+  var nativeSort = test.sort;
+
+  // IE8-
+  var FAILS_ON_UNDEFINED = fails(function () {
+    test.sort(undefined);
+  });
+  // V8 bug
+  var FAILS_ON_NULL = fails(function () {
+    test.sort(null);
+  });
+  // Old WebKit
+  var STRICT_METHOD = arrayMethodIsStrict('sort');
+
+  var STABLE_SORT = !fails(function () {
+    // feature detection can be too slow, so check engines versions
+    if (engineV8Version) return engineV8Version < 70;
+    if (engineFfVersion && engineFfVersion > 3) return;
+    if (engineIsIeOrEdge) return true;
+    if (engineWebkitVersion) return engineWebkitVersion < 603;
+
+    var result = '';
+    var code, chr, value, index;
+
+    // generate an array with more 512 elements (Chakra and old V8 fails only in this case)
+    for (code = 65; code < 76; code++) {
+      chr = String.fromCharCode(code);
+
+      switch (code) {
+        case 66: case 69: case 70: case 72: value = 3; break;
+        case 68: case 71: value = 4; break;
+        default: value = 2;
+      }
+
+      for (index = 0; index < 47; index++) {
+        test.push({ k: chr + index, v: value });
+      }
+    }
+
+    test.sort(function (a, b) { return b.v - a.v; });
+
+    for (index = 0; index < test.length; index++) {
+      chr = test[index].k.charAt(0);
+      if (result.charAt(result.length - 1) !== chr) result += chr;
+    }
+
+    return result !== 'DGBEFHACIJK';
+  });
+
+  var FORCED = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD || !STABLE_SORT;
+
+  var getSortCompare = function (comparefn) {
+    return function (x, y) {
+      if (y === undefined) return -1;
+      if (x === undefined) return 1;
+      if (comparefn !== undefined) return +comparefn(x, y) || 0;
+      return toString_1(x) > toString_1(y) ? 1 : -1;
+    };
+  };
+
+  // `Array.prototype.sort` method
+  // https://tc39.es/ecma262/#sec-array.prototype.sort
+  _export({ target: 'Array', proto: true, forced: FORCED }, {
+    sort: function sort(comparefn) {
+      if (comparefn !== undefined) aFunction(comparefn);
+
+      var array = toObject(this);
+
+      if (STABLE_SORT) return comparefn === undefined ? nativeSort.call(array) : nativeSort.call(array, comparefn);
+
+      var items = [];
+      var arrayLength = toLength(array.length);
+      var itemsLength, index;
+
+      for (index = 0; index < arrayLength; index++) {
+        if (index in array) items.push(array[index]);
+      }
+
+      items = arraySort(items, getSortCompare(comparefn));
+      itemsLength = items.length;
+      index = 0;
+
+      while (index < itemsLength) array[index] = items[index++];
+      while (index < arrayLength) delete array[index++];
+
+      return array;
+    }
+  });
+
+  /**
+   * Finds all Intro steps from the data-* attributes and the options.steps array
+   *
+   * @api private
+   * @param targetElm
+   * @returns {[]}
+   */
+
+  function fetchIntroSteps(targetElm) {
+    var _this = this;
+
+    var allIntroSteps = targetElm.querySelectorAll("*[data-intro]");
+    var introItems = [];
+
+    if (this._options.steps) {
+      //use steps passed programmatically
+      forEach(this._options.steps, function (step) {
+        var currentItem = cloneObject(step); //set the step
+
+        currentItem.step = introItems.length + 1;
+        currentItem.title = currentItem.title || ""; //use querySelector function only when developer used CSS selector
+
+        if (typeof currentItem.element === "string") {
+          //grab the element with given selector from the page
+          currentItem.element = document.querySelector(currentItem.element);
+        } //intro without element
+
+
+        if (typeof currentItem.element === "undefined" || currentItem.element === null) {
+          var floatingElementQuery = document.querySelector(".introjsFloatingElement");
+
+          if (floatingElementQuery === null) {
+            floatingElementQuery = _createElement("div", {
+              className: "introjsFloatingElement"
+            });
+            document.body.appendChild(floatingElementQuery);
+          }
+
+          currentItem.element = floatingElementQuery;
+          currentItem.position = "floating";
+        }
+
+        currentItem.position = currentItem.position || _this._options.tooltipPosition;
+        currentItem.scrollTo = currentItem.scrollTo || _this._options.scrollTo;
+
+        if (typeof currentItem.disableInteraction === "undefined") {
+          currentItem.disableInteraction = _this._options.disableInteraction;
+        }
+
+        if (currentItem.element !== null) {
+          introItems.push(currentItem);
+        }
+      });
+    } else {
+      //use steps from data-* annotations
+      var elmsLength = allIntroSteps.length;
+      var disableInteraction; //if there's no element to intro
+
+      if (elmsLength < 1) {
+        return [];
+      }
+
+      forEach(allIntroSteps, function (currentElement) {
+        // start intro for groups of elements
+        if (_this._options.group && currentElement.getAttribute("data-intro-group") !== _this._options.group) {
+          return;
+        } // skip hidden elements
+
+
+        if (currentElement.style.display === "none") {
+          return;
+        }
+
+        var step = parseInt(currentElement.getAttribute("data-step"), 10);
+
+        if (currentElement.hasAttribute("data-disable-interaction")) {
+          disableInteraction = !!currentElement.getAttribute("data-disable-interaction");
+        } else {
+          disableInteraction = _this._options.disableInteraction;
+        }
+
+        if (step > 0) {
+          introItems[step - 1] = {
+            element: currentElement,
+            title: currentElement.getAttribute("data-title") || "",
+            intro: currentElement.getAttribute("data-intro"),
+            step: parseInt(currentElement.getAttribute("data-step"), 10),
+            tooltipClass: currentElement.getAttribute("data-tooltipclass"),
+            highlightClass: currentElement.getAttribute("data-highlightclass"),
+            position: currentElement.getAttribute("data-position") || _this._options.tooltipPosition,
+            scrollTo: currentElement.getAttribute("data-scrollto") || _this._options.scrollTo,
+            disableInteraction: disableInteraction
+          };
+        }
+      }); //next add intro items without data-step
+      //todo: we need a cleanup here, two loops are redundant
+
+      var nextStep = 0;
+      forEach(allIntroSteps, function (currentElement) {
+        // start intro for groups of elements
+        if (_this._options.group && currentElement.getAttribute("data-intro-group") !== _this._options.group) {
+          return;
+        }
+
+        if (currentElement.getAttribute("data-step") === null) {
+          while (true) {
+            if (typeof introItems[nextStep] === "undefined") {
+              break;
+            } else {
+              nextStep++;
+            }
+          }
+
+          if (currentElement.hasAttribute("data-disable-interaction")) {
+            disableInteraction = !!currentElement.getAttribute("data-disable-interaction");
+          } else {
+            disableInteraction = _this._options.disableInteraction;
+          }
+
+          introItems[nextStep] = {
+            element: currentElement,
+            title: currentElement.getAttribute("data-title") || "",
+            intro: currentElement.getAttribute("data-intro"),
+            step: nextStep + 1,
+            tooltipClass: currentElement.getAttribute("data-tooltipclass"),
+            highlightClass: currentElement.getAttribute("data-highlightclass"),
+            position: currentElement.getAttribute("data-position") || _this._options.tooltipPosition,
+            scrollTo: currentElement.getAttribute("data-scrollto") || _this._options.scrollTo,
+            disableInteraction: disableInteraction
+          };
+        }
+      });
+    } //removing undefined/null elements
+
+
+    var tempIntroItems = [];
+
+    for (var z = 0; z < introItems.length; z++) {
+      if (introItems[z]) {
+        // copy non-falsy values to the end of the array
+        tempIntroItems.push(introItems[z]);
+      }
+    }
+
+    introItems = tempIntroItems; //Ok, sort all items with given steps
+
+    introItems.sort(function (a, b) {
+      return a.step - b.step;
+    });
+    return introItems;
+  }
+
+  /**
+   * Update placement of the intro objects on the screen
+   * @api private
+   * @param {boolean} refreshSteps to refresh the intro steps as well
+   */
+
+  function refresh(refreshSteps) {
+    var referenceLayer = document.querySelector(".introjs-tooltipReferenceLayer");
+    var helperLayer = document.querySelector(".introjs-helperLayer");
+    var disableInteractionLayer = document.querySelector(".introjs-disableInteraction"); // re-align intros
+
+    setHelperLayerPosition.call(this, helperLayer);
+    setHelperLayerPosition.call(this, referenceLayer);
+    setHelperLayerPosition.call(this, disableInteractionLayer);
+
+    if (refreshSteps) {
+      this._introItems = fetchIntroSteps.call(this, this._targetElement);
+
+      _recreateBullets.call(this, referenceLayer, this._introItems[this._currentStep]);
+
+      _updateProgressBar.call(this, referenceLayer);
+    } // re-align tooltip
+
+
+    if (this._currentStep !== undefined && this._currentStep !== null) {
+      var oldArrowLayer = document.querySelector(".introjs-arrow");
+      var oldtooltipContainer = document.querySelector(".introjs-tooltip");
+      placeTooltip.call(this, this._introItems[this._currentStep].element, oldtooltipContainer, oldArrowLayer);
+    } //re-align hints
+
+
+    reAlignHints.call(this);
+    return this;
+  }
+
+  function onResize() {
+    refresh.call(this);
+  }
+
+  /**
+   * Removes `element` from `parentElement`
+   *
+   * @param {Element} element
+   * @param {Boolean} [animate=false]
+   */
+
+  function removeChild(element, animate) {
+    if (!element || !element.parentElement) return;
+    var parentElement = element.parentElement;
+
+    if (animate) {
+      setStyle(element, {
+        opacity: "0"
+      });
+      window.setTimeout(function () {
+        try {
+          // removeChild(..) throws an exception if the child has already been removed (https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild)
+          // this try-catch is added to make sure this function doesn't throw an exception if the child has been removed
+          // this scenario can happen when start()/exit() is called multiple times and the helperLayer is removed by the
+          // previous exit() call (note: this is a timeout)
+          parentElement.removeChild(element);
+        } catch (e) {}
+      }, 500);
+    } else {
+      parentElement.removeChild(element);
+    }
+  }
+
+  /**
+   * Exit from intro
+   *
+   * @api private
+   * @method _exitIntro
+   * @param {Object} targetElement
+   * @param {Boolean} force - Setting to `true` will skip the result of beforeExit callback
+   */
+
+  function exitIntro(targetElement, force) {
+    var continueExit = true; // calling onbeforeexit callback
+    //
+    // If this callback return `false`, it would halt the process
+
+    if (this._introBeforeExitCallback !== undefined) {
+      continueExit = this._introBeforeExitCallback.call(this);
+    } // skip this check if `force` parameter is `true`
+    // otherwise, if `onbeforeexit` returned `false`, don't exit the intro
+
+
+    if (!force && continueExit === false) return; // remove overlay layers from the page
+
+    var overlayLayers = targetElement.querySelectorAll(".introjs-overlay");
+
+    if (overlayLayers && overlayLayers.length) {
+      forEach(overlayLayers, function (overlayLayer) {
+        return removeChild(overlayLayer);
+      });
+    } //remove all helper layers
+
+
+    var helperLayer = targetElement.querySelector(".introjs-helperLayer");
+    removeChild(helperLayer, true);
+    var referenceLayer = targetElement.querySelector(".introjs-tooltipReferenceLayer");
+    removeChild(referenceLayer); //remove disableInteractionLayer
+
+    var disableInteractionLayer = targetElement.querySelector(".introjs-disableInteraction");
+    removeChild(disableInteractionLayer); //remove intro floating element
+
+    var floatingElement = document.querySelector(".introjsFloatingElement");
+    removeChild(floatingElement);
+    removeShowElement(); //clean listeners
+
+    DOMEvent.off(window, "keydown", onKeyDown, this, true);
+    DOMEvent.off(window, "resize", onResize, this, true); //check if any callback is defined
+
+    if (this._introExitCallback !== undefined) {
+      this._introExitCallback.call(this);
+    } //set the step to zero
+
+
+    this._currentStep = undefined;
+  }
+
+  /**
+   * Add overlay layer to the page
+   *
+   * @api private
+   * @method _addOverlayLayer
+   * @param {Object} targetElm
+   */
+
+  function addOverlayLayer(targetElm) {
+    var _this = this;
+
+    var overlayLayer = _createElement("div", {
+      className: "introjs-overlay"
+    });
+    setStyle(overlayLayer, {
+      top: 0,
+      bottom: 0,
+      left: 0,
+      right: 0,
+      position: "fixed"
+    });
+    targetElm.appendChild(overlayLayer);
+
+    if (this._options.exitOnOverlayClick === true) {
+      setStyle(overlayLayer, {
+        cursor: "pointer"
+      });
+
+      overlayLayer.onclick = function () {
+        exitIntro.call(_this, targetElm);
+      };
+    }
+
+    return true;
+  }
+
+  /**
+   * Initiate a new introduction/guide from an element in the page
+   *
+   * @api private
+   * @method introForElement
+   * @param {Object} targetElm
+   * @returns {Boolean} Success or not?
+   */
+
+  function introForElement(targetElm) {
+    //set it to the introJs object
+    var steps = fetchIntroSteps.call(this, targetElm);
+
+    if (steps.length === 0) {
+      return false;
+    }
+
+    this._introItems = steps; //add overlay layer to the page
+
+    if (addOverlayLayer.call(this, targetElm)) {
+      //then, start the show
+      nextStep.call(this);
+
+      if (this._options.keyboardNavigation) {
+        DOMEvent.on(window, "keydown", onKeyDown, this, true);
+      } //for window resize
+
+
+      DOMEvent.on(window, "resize", onResize, this, true);
+    }
+
+    return false;
+  }
+
+  var version = "4.2.2";
+
+  /**
+   * IntroJs main class
+   *
+   * @class IntroJs
+   */
+
+  function IntroJs(obj) {
+    this._targetElement = obj;
+    this._introItems = [];
+    this._options = {
+      /* Next button label in tooltip box */
+      nextLabel: "Next",
+
+      /* Previous button label in tooltip box */
+      prevLabel: "Back",
+
+      /* Skip button label in tooltip box */
+      skipLabel: "×",
+
+      /* Done button label in tooltip box */
+      doneLabel: "Done",
+
+      /* Hide previous button in the first step? Otherwise, it will be disabled button. */
+      hidePrev: false,
+
+      /* Hide next button in the last step? Otherwise, it will be disabled button (note: this will also hide the "Done" button) */
+      hideNext: false,
+
+      /* Change the Next button to Done in the last step of the intro? otherwise, it will render a disabled button */
+      nextToDone: true,
+
+      /* Default tooltip box position */
+      tooltipPosition: "bottom",
+
+      /* Next CSS class for tooltip boxes */
+      tooltipClass: "",
+
+      /* Start intro for a group of elements */
+      group: "",
+
+      /* CSS class that is added to the helperLayer */
+      highlightClass: "",
+
+      /* Close introduction when pressing Escape button? */
+      exitOnEsc: true,
+
+      /* Close introduction when clicking on overlay layer? */
+      exitOnOverlayClick: true,
+
+      /* Show step numbers in introduction? */
+      showStepNumbers: false,
+
+      /* Let user use keyboard to navigate the tour? */
+      keyboardNavigation: true,
+
+      /* Show tour control buttons? */
+      showButtons: true,
+
+      /* Show tour bullets? */
+      showBullets: true,
+
+      /* Show tour progress? */
+      showProgress: false,
+
+      /* Scroll to highlighted element? */
+      scrollToElement: true,
+
+      /*
+       * Should we scroll the tooltip or target element?
+       *
+       * Options are: 'element' or 'tooltip'
+       */
+      scrollTo: "element",
+
+      /* Padding to add after scrolling when element is not in the viewport (in pixels) */
+      scrollPadding: 30,
+
+      /* Set the overlay opacity */
+      overlayOpacity: 0.5,
+
+      /* To determine the tooltip position automatically based on the window.width/height */
+      autoPosition: true,
+
+      /* Precedence of positions, when auto is enabled */
+      positionPrecedence: ["bottom", "top", "right", "left"],
+
+      /* Disable an interaction with element? */
+      disableInteraction: false,
+
+      /* Set how much padding to be used around helper element */
+      helperElementPadding: 10,
+
+      /* Default hint position */
+      hintPosition: "top-middle",
+
+      /* Hint button label */
+      hintButtonLabel: "Got it",
+
+      /* Adding animation to hints? */
+      hintAnimation: true,
+
+      /* additional classes to put on the buttons */
+      buttonClass: "introjs-button",
+
+      /* additional classes to put on progress bar */
+      progressBarAdditionalClass: false
+    };
+  }
+
+  var introJs = function introJs(targetElm) {
     var instance;
 
-    if (typeof (targetElm) === 'object') {
+    if (_typeof(targetElm) === "object") {
       //Ok, create a new instance
       instance = new IntroJs(targetElm);
-
-    } else if (typeof (targetElm) === 'string') {
+    } else if (typeof targetElm === "string") {
       //select the target element with query selector
       var targetElement = document.querySelector(targetElm);
 
       if (targetElement) {
         instance = new IntroJs(targetElement);
       } else {
-        throw new Error('There is no element with given selector.');
+        throw new Error("There is no element with given selector.");
       }
     } else {
       instance = new IntroJs(document.body);
-    }
-    // add instance to list of _instances
-    // passing group to _stamp to increment
+    } // add instance to list of _instances
+    // passing group to stamp to increment
     // from 0 onward somewhat reliably
-    introJs.instances[ _stamp(instance, 'introjs-instance') ] = instance;
 
+
+    introJs.instances[stamp(instance, "introjs-instance")] = instance;
     return instance;
   };
-
   /**
    * Current IntroJs version
    *
    * @property version
    * @type String
    */
-  introJs.version = VERSION;
 
+
+  introJs.version = version;
   /**
-  * key-val object helper for introJs instances
-  *
-  * @property instances
-  * @type Object
-  */
-  introJs.instances = {};
+   * key-val object helper for introJs instances
+   *
+   * @property instances
+   * @type Object
+   */
 
-  //Prototype
+  introJs.instances = {}; //Prototype
+
   introJs.fn = IntroJs.prototype = {
-    clone: function () {
+    clone: function clone() {
       return new IntroJs(this);
     },
-    setOption: function(option, value) {
+    setOption: function setOption(option, value) {
       this._options[option] = value;
       return this;
     },
-    setOptions: function(options) {
-      this._options = _mergeOptions(this._options, options);
+    setOptions: function setOptions(options) {
+      this._options = mergeOptions(this._options, options);
       return this;
     },
-    start: function (group) {
-      _introForElement.call(this, this._targetElement, group);
+    start: function start() {
+      introForElement.call(this, this._targetElement);
       return this;
     },
-    goToStep: function(step) {
-      _goToStep.call(this, step);
+    goToStep: function goToStep$1(step) {
+      goToStep.call(this, step);
+
       return this;
     },
-    addStep: function(options) {
+    addStep: function addStep(options) {
       if (!this._options.steps) {
         this._options.steps = [];
       }
@@ -2383,149 +4590,173 @@
 
       return this;
     },
-    addSteps: function(steps) {
+    addSteps: function addSteps(steps) {
       if (!steps.length) return;
 
-      for(var index = 0; index < steps.length; index++) {
+      for (var index = 0; index < steps.length; index++) {
         this.addStep(steps[index]);
       }
 
       return this;
     },
-    goToStepNumber: function(step) {
-      _goToStepNumber.call(this, step);
+    goToStepNumber: function goToStepNumber$1(step) {
+      goToStepNumber.call(this, step);
 
       return this;
     },
-    nextStep: function() {
-      _nextStep.call(this);
+    nextStep: function nextStep$1() {
+      nextStep.call(this);
+
       return this;
     },
-    previousStep: function() {
-      _previousStep.call(this);
+    previousStep: function previousStep$1() {
+      previousStep.call(this);
+
       return this;
     },
-    exit: function(force) {
-      _exitIntro.call(this, this._targetElement, force);
+    currentStep: function currentStep$1() {
+      return currentStep.call(this);
+    },
+    exit: function exit(force) {
+      exitIntro.call(this, this._targetElement, force);
       return this;
     },
-    refresh: function() {
-      _refresh.call(this);
+    refresh: function refresh$1(refreshSteps) {
+      refresh.call(this, refreshSteps);
+
       return this;
     },
-    onbeforechange: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onbeforechange: function onbeforechange(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._introBeforeChangeCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onbeforechange was not a function');
+        throw new Error("Provided callback for onbeforechange was not a function");
       }
+
       return this;
     },
-    onchange: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onchange: function onchange(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._introChangeCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onchange was not a function.');
+        throw new Error("Provided callback for onchange was not a function.");
       }
+
       return this;
     },
-    onafterchange: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onafterchange: function onafterchange(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._introAfterChangeCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onafterchange was not a function');
+        throw new Error("Provided callback for onafterchange was not a function");
       }
+
       return this;
     },
-    oncomplete: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    oncomplete: function oncomplete(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._introCompleteCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for oncomplete was not a function.');
+        throw new Error("Provided callback for oncomplete was not a function.");
       }
+
       return this;
     },
-    onhintsadded: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onhintsadded: function onhintsadded(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._hintsAddedCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onhintsadded was not a function.');
+        throw new Error("Provided callback for onhintsadded was not a function.");
       }
+
       return this;
     },
-    onhintclick: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onhintclick: function onhintclick(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._hintClickCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onhintclick was not a function.');
+        throw new Error("Provided callback for onhintclick was not a function.");
       }
+
       return this;
     },
-    onhintclose: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onhintclose: function onhintclose(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._hintCloseCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onhintclose was not a function.');
+        throw new Error("Provided callback for onhintclose was not a function.");
       }
+
       return this;
     },
-    onexit: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onexit: function onexit(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._introExitCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onexit was not a function.');
+        throw new Error("Provided callback for onexit was not a function.");
       }
+
       return this;
     },
-    onskip: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onskip: function onskip(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._introSkipCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onskip was not a function.');
+        throw new Error("Provided callback for onskip was not a function.");
       }
+
       return this;
     },
-    onbeforeexit: function(providedCallback) {
-      if (typeof (providedCallback) === 'function') {
+    onbeforeexit: function onbeforeexit(providedCallback) {
+      if (typeof providedCallback === "function") {
         this._introBeforeExitCallback = providedCallback;
       } else {
-        throw new Error('Provided callback for onbeforeexit was not a function.');
+        throw new Error("Provided callback for onbeforeexit was not a function.");
       }
+
       return this;
     },
-    addHints: function() {
-      _populateHints.call(this, this._targetElement);
+    addHints: function addHints() {
+      populateHints.call(this, this._targetElement);
       return this;
     },
-    hideHint: function (stepId) {
-      _hideHint.call(this, stepId);
+    hideHint: function hideHint$1(stepId) {
+      hideHint.call(this, stepId);
+
       return this;
     },
-    hideHints: function () {
-      _hideHints.call(this);
+    hideHints: function hideHints$1() {
+      hideHints.call(this);
+
       return this;
     },
-    showHint: function (stepId) {
-      _showHint.call(this, stepId);
+    showHint: function showHint$1(stepId) {
+      showHint.call(this, stepId);
+
       return this;
     },
-    showHints: function () {
-      _showHints.call(this);
+    showHints: function showHints$1() {
+      showHints.call(this);
+
       return this;
     },
-    removeHints: function () {
-      _removeHints.call(this);
+    removeHints: function removeHints$1() {
+      removeHints.call(this);
+
       return this;
     },
-    removeHint: function (stepId) {
-      _removeHint.call(this, stepId);
+    removeHint: function removeHint$1(stepId) {
+      removeHint().call(this, stepId);
+
       return this;
     },
-    showHintDialog: function (stepId) {
-      _showHintDialog.call(this, stepId);
+    showHintDialog: function showHintDialog$1(stepId) {
+      showHintDialog.call(this, stepId);
+
       return this;
     }
   };
 
   return introJs;
-});
+
+})));
diff --git a/dev/js/spec/tourSpec.js b/dev/js/spec/tourSpec.js
index 3cd1a5b..e65d273 100644
--- a/dev/js/spec/tourSpec.js
+++ b/dev/js/spec/tourSpec.js
@@ -459,9 +459,9 @@
      let welc = document.createElement("DIV");
      welc.innerHTML = loc.TOUR_welc;
      expect(document.querySelector(".introjs-tooltiptext").textContent).toEqual(welc.textContent);
-     expect(document.querySelector(".introjs-skipbutton").textContent).toEqual(loc.TOUR_lskip);
      expect(document.querySelector(".introjs-prevbutton").textContent).toEqual(loc.TOUR_lprev);
      expect(document.querySelector(".introjs-nextbutton").textContent).toEqual(loc.TOUR_lnext);
+     expect(document.querySelector(".introjs-skipbutton")).toBeDefined();
      searchTour.exit();
      
      for(let i = 2; i <= totalSteps; i++){
@@ -483,6 +483,7 @@
        case totalSteps:
        expect(document.querySelector(".introjs-donebutton").textContent).toEqual(loc.TOUR_ldoneSearch);
        expect(document.querySelector(".introjs-prevbutton").textContent).toEqual(loc.TOUR_lprev);
+       expect(document.querySelector(".introjs-skipbutton")).toBeDefined();
        break;
        }
        searchTour.exit();
@@ -494,9 +495,9 @@
      resultTour.start(resultkor);
      let totalStepsR = resultTour.stepCount;
      expect(document.querySelector(".introjs-tooltiptext").textContent).toEqual(loc.TOUR_kwic);
-     expect(document.querySelector(".introjs-skipbutton").textContent).toEqual(loc.TOUR_lskip);
      expect(document.querySelector(".introjs-prevbutton").textContent).toEqual(loc.TOUR_lprev);
      expect(document.querySelector(".introjs-nextbutton").textContent).toEqual(loc.TOUR_lnext);
+     expect(document.querySelector(".introjs-skipbutton")).toBeDefined();
      resultTour.exit();
      for(let i = 2; i <= totalStepsR; i++){
        resultTour.goToStepNumber(i);
diff --git a/dev/js/src/loc/de.js b/dev/js/src/loc/de.js
index 6daed13..a7c0080 100644
--- a/dev/js/src/loc/de.js
+++ b/dev/js/src/loc/de.js
@@ -37,22 +37,19 @@
   //Corpus statistic
   loc.SHOW_STAT = 'Korpusstatistik';
   loc.REFRESH = 'Neu laden';
-  //verbose description, for title attributes for example
-  //loc.VERB_SHOWSTAT = 'Korpusstatistik';
-
+ 
   loc.NEW_CONSTRAINT = 'Neue Bedingung';
 
   //Guided Tour:Buttonlabels
-  loc.TOUR_lskip = "Abbrechen";
   loc.TOUR_lprev = "Zurück";
   loc.TOUR_lnext = "Weiter";
   loc.TOUR_ldone = "Beenden";
   loc.TOUR_ldoneSearch = "Suchen";
   
   //Guided Tour: Steps
-  loc.TOUR_welc = "<span class = 'tgreeting'>Willkommen zur KorAP Tour! </span> " +
-  "<p class='pfirstStep'> Hier zeigen wir Ihnen einige wichtige Funktionalitäten von KorAP. " +
-  "Wir führen Sie Schritt bei Schritt anhand eines Beispiels durch die Anwendung. </p>";  
+  loc.TOUR_welcti = " <span class='tgreeting'> Willkommen zur KorAP Tour! </span>";
+  loc.TOUR_welc = "Hier zeigen wir Ihnen einige wichtige Funktionalitäten von KorAP. " +
+  		"Wir führen Sie Schritt bei Schritt anhand eines Beispiels durch die Anwendung.";  
   loc.TOUR_sear1 = "Eingabe der Suchanfrage, zum Beispiel die Suche nach '" + loc.TOUR_Qexample + "'." ;
   loc.TOUR_searAnnot ="Für die Suche nach Annotationen steht der Annotationsassistent zur Verfügung.";
   loc.TOUR_annotAss = "Der Annotationsassistent erleichert die Formulierung von Suchanfragen mit Annotationen.";
diff --git a/dev/js/src/tour/tours.js b/dev/js/src/tour/tours.js
index d67b518..8f6f042 100644
--- a/dev/js/src/tour/tours.js
+++ b/dev/js/src/tour/tours.js
@@ -11,17 +11,16 @@
   //needed for localization of labels and contents of the tour
   const loc   = KorAP.Locale;
 
-  //labels for nextStep, previousStep, done and abort
-  loc.TOUR_lskip = loc.TOUR_lskip || "Abort";
+  //labels for nextStep, previousStep and done
   loc.TOUR_lprev = loc.TOUR_lprev || "Back";
   loc.TOUR_lnext = loc.TOUR_lnext || "Next";
   loc.TOUR_ldone = loc.TOUR_ldone || "Done";
   loc.TOUR_ldoneSearch = loc.TOUR_ldoneSearch || "Search";
   
   //localization guided tour gTstartSearch
-  loc.TOUR_welc = loc.TOUR_welc || "<span class='tgreeting'> Welcome to our guided tour!</span>" +
-  		                           "<p class='pfirstStep'> This tour should give you a quick introduction to KorAP. " +
-  		                           "We lead you step by step through an example. </p>"; 
+  loc.TOUR_welcti = loc.TOUR_welcti || "<span class='tgreeting'> Welcome to our guided tour! </span>";
+  loc.TOUR_welc = loc.TOUR_welc || "This tour should give you a quick introduction to KorAP. " +
+  		                           "We lead you step by step through an example."; 
   loc.TOUR_sear1 = loc.TOUR_sear1 || "Input field for the query, for example the search for '" +  loc.TOUR_Qexample + "'.";
   loc.TOUR_searAnnot = loc.TOUR_searAnnot || "Annotation helper";
   loc.TOUR_annotAss =  loc.TOUR_annotAss || "The assistant displays the annotations of the different layers and helps to formulate queries.";
@@ -48,7 +47,6 @@
   
   //localization of button labels
   let labelOpts= {
-      'skipLabel': loc.TOUR_lskip, 
       'prevLabel': loc.TOUR_lprev,
       'nextLabel': loc.TOUR_lnext,
       'doneLabel': loc.TOUR_ldone,
@@ -58,10 +56,10 @@
   //usability options of tours
   let usabilityOpts ={
       'showBullets': false,
-      'overlayOpacity': 0.7,
+      'overlayOpacity': 0.5,
       'exitOnOverlayClick': false,
-      'disableInteraction': true,      
-      'hideNext': true,
+      'disableInteraction': true,  
+      'tooltipClass': 'customTooltip',
       'hidePrev': true
   };
   
@@ -75,7 +73,6 @@
     gTstartSearch:function(elparam){
       let intro = introClass();
       intro.setOptions(labelOpts);
-      intro.setOption('tooltipClass', 'gTstartSearch');
       /*
        * Sets button labels for the last step of the tour
        * Because Kalamar is a multipage webapplication, this tours starts by
@@ -96,6 +93,7 @@
       //steps of the example tour
       let Steps =[
         {
+          title: loc.TOUR_welcti,
           intro: loc.TOUR_welc,
         },
         {
@@ -139,7 +137,7 @@
           position: "bottom",
         },  
         {
-          element:'#glimpse',
+          element: '#glimpse',
           intro: loc.TOUR_glimpse,
           position: "bottom",
         },