Create an array scroll positions from descending elements
14182
function getElmScrollRecursive(root) {
	return Array.from(root.children).reduce((scrolls, elm) => {
		const scroll = getScroll(elm);
		if (scroll) {
			scrolls.push(scroll);
		}
		return scrolls.concat(getElmScrollRecursive(elm));
	}, []);
}
858955
def scroll_down (self): # <ESC>D
        ''''''

        # Screen is indexed from 1, but arrays are indexed from 0.
        s = self.scroll_row_start - 1
        e = self.scroll_row_end - 1
        self.w[s+1:e+1] = copy.deepcopy(self.w[s:e])
1091143
function () {
        this.top = document.body.scrollTop;
        this.left = document.body.scrollLeft;
        this.bottom = this.top + docElement.clientHeight;
        this.right = this.left + docElement.clientWidth;
    }
976901
function JScrollPane(elem, s)
    {
      var settings, jsp = this, pane, paneWidth, paneHeight, container, contentWidth, contentHeight,
        percentInViewH, percentInViewV, isScrollableV, isScrollableH, verticalDrag, dragMaxY,
        verticalDragPosition, horizontalDrag, dragMaxX, horizontalDragPosition,
        verticalBar, verticalTrack, scrollbarWidth, verticalTrackHeight, verticalDragHeight, arrowUp, arrowDown,
        horizontalBar, horizontalTrack, horizontalTrackWidth, horizontalDragWidth, arrowLeft, arrowRight,
        reinitialiseInterval, originalPadding, originalPaddingTotalWidth, previousContentWidth,
        wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false,
        originalElement = elem.clone(false, false).empty(),
        mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp';

      originalPadding = elem.css('paddingTop') + ' ' +
                elem.css('paddingRight') + ' ' +
                elem.css('paddingBottom') + ' ' +
                elem.css('paddingLeft');
      originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) +
                    (parseInt(elem.css('paddingRight'), 10) || 0);

      function initialise(s)
      {

        var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY,
            hasContainingSpaceChanged, originalScrollTop, originalScrollLeft,
            maintainAtBottom = false, maintainAtRight = false;

        settings = s;

        if (pane === undefined) {
          originalScrollTop = elem.scrollTop();
          originalScrollLeft = elem.scrollLeft();

          elem.css(
            {
              overflow: 'hidden',
              padding: 0
            }
          );
          // TODO: Deal with where width/ height is 0 as it probably means the element is hidden and we should
          // come back to it later and check once it is unhidden...
          paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
          paneHeight = elem.innerHeight();

          elem.width(paneWidth);
          
          pane = $('<div class="jspPane" />').css('padding', originalPadding).append(elem.children());
          container = $('<div class="jspContainer" />')
            .css({
              'width': paneWidth + 'px',
              'height': paneHeight + 'px'
            }
          ).append(pane).appendTo(elem);

          /*
          // Move any margins from the first and last children up to the container so they can still
          // collapse with neighbouring elements as they would before jScrollPane 
          firstChild = pane.find(':first-child');
          lastChild = pane.find(':last-child');
          elem.css(
            {
              'margin-top': firstChild.css('margin-top'),
              'margin-bottom': lastChild.css('margin-bottom')
            }
          );
          firstChild.css('margin-top', 0);
          lastChild.css('margin-bottom', 0);
          */
        } else {
          elem.css('width', '');

          maintainAtBottom = settings.stickToBottom && isCloseToBottom();
          maintainAtRight  = settings.stickToRight  && isCloseToRight();

          hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight;

          if (hasContainingSpaceChanged) {
            paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
            paneHeight = elem.innerHeight();
            container.css({
              width: paneWidth + 'px',
              height: paneHeight + 'px'
            });
          }

          // If nothing changed since last check...
          if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) {
            elem.width(paneWidth);
            return;
          }
          previousContentWidth = contentWidth;
          
          pane.css('width', '');
          elem.width(paneWidth);

          container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end();
        }

        pane.css('overflow', 'auto');
        if (s.contentWidth) {
          contentWidth = s.contentWidth;
        } else {
          contentWidth = pane[0].scrollWidth;
        }
        contentHeight = pane[0].scrollHeight;
        pane.css('overflow', '');

        percentInViewH = contentWidth / paneWidth;
        percentInViewV = contentHeight / paneHeight;
        isScrollableV = percentInViewV > 1;

        isScrollableH = percentInViewH > 1;

        //console.log(paneWidth, paneHeight, contentWidth, contentHeight, percentInViewH, percentInViewV, isScrollableH, isScrollableV);

        if (!(isScrollableH || isScrollableV)) {
          elem.removeClass('jspScrollable');
          pane.css({
            top: 0,
            width: container.width() - originalPaddingTotalWidth
          });
          removeMousewheel();
          removeFocusHandler();
          removeKeyboardNav();
          removeClickOnTrack();
        } else {
          elem.addClass('jspScrollable');

          isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition);
          if (isMaintainingPositon) {
            lastContentX = contentPositionX();
            lastContentY = contentPositionY();
          }

          initialiseVerticalScroll();
          initialiseHorizontalScroll();
          resizeScrollbars();

          if (isMaintainingPositon) {
            scrollToX(maintainAtRight  ? (contentWidth  - paneWidth ) : lastContentX, false);
            scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false);
          }

          initFocusHandler();
          initMousewheel();
          initTouch();
          
          if (settings.enableKeyboardNavigation) {
            initKeyboardNav();
          }
          if (settings.clickOnTrack) {
            initClickOnTrack();
          }
          
          observeHash();
          if (settings.hijackInternalLinks) {
            hijackInternalLinks();
          }
        }

        if (settings.autoReinitialise && !reinitialiseInterval) {
          reinitialiseInterval = setInterval(
            function()
            {
              initialise(settings);
            },
            settings.autoReinitialiseDelay
          );
        } else if (!settings.autoReinitialise && reinitialiseInterval) {
          clearInterval(reinitialiseInterval);
        }

        originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false);
        originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false);

        elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]);
      }

      function initialiseVerticalScroll()
      {
        if (isScrollableV) {

          container.append(
            $('<div class="jspVerticalBar" />').append(
              $('<div class="jspCap jspCapTop" />'),
              $('<div class="jspTrack" />').append(
                $('<div class="jspDrag" />').append(
                  $('<div class="jspDragTop" />'),
                  $('<div class="jspDragBottom" />')
                )
              ),
              $('<div class="jspCap jspCapBottom" />')
            )
          );

          verticalBar = container.find('>.jspVerticalBar');
          verticalTrack = verticalBar.find('>.jspTrack');
          verticalDrag = verticalTrack.find('>.jspDrag');

          if (settings.showArrows) {
            arrowUp = $('<a class="jspArrow jspArrowUp" />').bind(
              'mousedown.jsp', getArrowScroll(0, -1)
            ).bind('click.jsp', nil);
            arrowDown = $('<a class="jspArrow jspArrowDown" />').bind(
              'mousedown.jsp', getArrowScroll(0, 1)
            ).bind('click.jsp', nil);
            if (settings.arrowScrollOnHover) {
              arrowUp.bind('mouseover.jsp', getArrowScroll(0, -1, arrowUp));
              arrowDown.bind('mouseover.jsp', getArrowScroll(0, 1, arrowDown));
            }

            appendArrows(verticalTrack, settings.verticalArrowPositions, arrowUp, arrowDown);
          }

          verticalTrackHeight = paneHeight;
          container.find('>.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow').each(
            function()
            {
              verticalTrackHeight -= $(this).outerHeight();
            }
          );


          verticalDrag.hover(
            function()
            {
              verticalDrag.addClass('jspHover');
            },
            function()
            {
              verticalDrag.removeClass('jspHover');
            }
          ).bind(
            'mousedown.jsp',
            function(e)
            {
              // Stop IE from allowing text selection
              $('html').bind('dragstart.jsp selectstart.jsp', nil);

              verticalDrag.addClass('jspActive');

              var startY = e.pageY - verticalDrag.position().top;

              $('html').bind(
                'mousemove.jsp',
                function(e)
                {
                  positionDragY(e.pageY - startY, false);
                }
              ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
              return false;
            }
          );
          sizeVerticalScrollbar();
        }
      }

      function sizeVerticalScrollbar()
      {
        verticalTrack.height(verticalTrackHeight + 'px');
        verticalDragPosition = 0;
        scrollbarWidth = settings.verticalGutter + verticalTrack.outerWidth();

        // Make the pane thinner to allow for the vertical scrollbar
        pane.width(paneWidth - scrollbarWidth - originalPaddingTotalWidth);

        // Add margin to the left of the pane if scrollbars are on that side (to position
        // the scrollbar on the left or right set it's left or right property in CSS)
        try {
          if (verticalBar.position().left === 0) {
            pane.css('margin-left', scrollbarWidth + 'px');
          }
        } catch (err) {
        }
      }

      function initialiseHorizontalScroll()
      {
        if (isScrollableH) {

          container.append(
            $('<div class="jspHorizontalBar" />').append(
              $('<div class="jspCap jspCapLeft" />'),
              $('<div class="jspTrack" />').append(
                $('<div class="jspDrag" />').append(
                  $('<div class="jspDragLeft" />'),
                  $('<div class="jspDragRight" />')
                )
              ),
              $('<div class="jspCap jspCapRight" />')
            )
          );

          horizontalBar = container.find('>.jspHorizontalBar');
          horizontalTrack = horizontalBar.find('>.jspTrack');
          horizontalDrag = horizontalTrack.find('>.jspDrag');

          if (settings.showArrows) {
            arrowLeft = $('<a class="jspArrow jspArrowLeft" />').bind(
              'mousedown.jsp', getArrowScroll(-1, 0)
            ).bind('click.jsp', nil);
            arrowRight = $('<a class="jspArrow jspArrowRight" />').bind(
              'mousedown.jsp', getArrowScroll(1, 0)
            ).bind('click.jsp', nil);
            if (settings.arrowScrollOnHover) {
              arrowLeft.bind('mouseover.jsp', getArrowScroll(-1, 0, arrowLeft));
              arrowRight.bind('mouseover.jsp', getArrowScroll(1, 0, arrowRight));
            }
            appendArrows(horizontalTrack, settings.horizontalArrowPositions, arrowLeft, arrowRight);
          }

          horizontalDrag.hover(
            function()
            {
              horizontalDrag.addClass('jspHover');
            },
            function()
            {
              horizontalDrag.removeClass('jspHover');
            }
          ).bind(
            'mousedown.jsp',
            function(e)
            {
              // Stop IE from allowing text selection
              $('html').bind('dragstart.jsp selectstart.jsp', nil);

              horizontalDrag.addClass('jspActive');

              var startX = e.pageX - horizontalDrag.position().left;

              $('html').bind(
                'mousemove.jsp',
                function(e)
                {
                  positionDragX(e.pageX - startX, false);
                }
              ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
              return false;
            }
          );
          horizontalTrackWidth = container.innerWidth();
          sizeHorizontalScrollbar();
        }
      }

      function sizeHorizontalScrollbar()
      {
        container.find('>.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow').each(
          function()
          {
            horizontalTrackWidth -= $(this).outerWidth();
          }
        );

        horizontalTrack.width(horizontalTrackWidth + 'px');
        horizontalDragPosition = 0;
      }

      function resizeScrollbars()
      {
        if (isScrollableH && isScrollableV) {
          var horizontalTrackHeight = horizontalTrack.outerHeight(),
            verticalTrackWidth = verticalTrack.outerWidth();
          verticalTrackHeight -= horizontalTrackHeight;
          $(horizontalBar).find('>.jspCap:visible,>.jspArrow').each(
            function()
            {
              horizontalTrackWidth += $(this).outerWidth();
            }
          );
          horizontalTrackWidth -= verticalTrackWidth;
          paneHeight -= verticalTrackWidth;
          paneWidth -= horizontalTrackHeight;
          horizontalTrack.parent().append(
            $('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
          );
          sizeVerticalScrollbar();
          sizeHorizontalScrollbar();
        }
        // reflow content
        if (isScrollableH) {
          pane.width((container.outerWidth() - originalPaddingTotalWidth) + 'px');
        }
        contentHeight = pane.outerHeight();
        percentInViewV = contentHeight / paneHeight;

        if (isScrollableH) {
          horizontalDragWidth = Math.ceil(1 / percentInViewH * horizontalTrackWidth);
          if (horizontalDragWidth > settings.horizontalDragMaxWidth) {
            horizontalDragWidth = settings.horizontalDragMaxWidth;
          } else if (horizontalDragWidth < settings.horizontalDragMinWidth) {
            horizontalDragWidth = settings.horizontalDragMinWidth;
          }
          horizontalDrag.width(horizontalDragWidth + 'px');
          dragMaxX = horizontalTrackWidth - horizontalDragWidth;
          _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons
        }
        if (isScrollableV) {
          verticalDragHeight = Math.ceil(1 / percentInViewV * verticalTrackHeight);
          if (verticalDragHeight > settings.verticalDragMaxHeight) {
            verticalDragHeight = settings.verticalDragMaxHeight;
          } else if (verticalDragHeight < settings.verticalDragMinHeight) {
            verticalDragHeight = settings.verticalDragMinHeight;
          }
          verticalDrag.height(verticalDragHeight + 'px');
          dragMaxY = verticalTrackHeight - verticalDragHeight;
          _positionDragY(verticalDragPosition); // To update the state for the arrow buttons
        }
      }

      function appendArrows(ele, p, a1, a2)
      {
        var p1 = "before", p2 = "after", aTemp;
        
        // Sniff for mac... Is there a better way to determine whether the arrows would naturally appear
        // at the top or the bottom of the bar?
        if (p == "os") {
          p = /Mac/.test(navigator.platform) ? "after" : "split";
        }
        if (p == p1) {
          p2 = p;
        } else if (p == p2) {
          p1 = p;
          aTemp = a1;
          a1 = a2;
          a2 = aTemp;
        }

        ele[p1](a1)[p2](a2);
      }

      function getArrowScroll(dirX, dirY, ele)
      {
        return function()
        {
          arrowScroll(dirX, dirY, this, ele);
          this.blur();
          return false;
        };
      }

      function arrowScroll(dirX, dirY, arrow, ele)
      {
        arrow = $(arrow).addClass('jspActive');

        var eve,
          scrollTimeout,
          isFirst = true,
          doScroll = function()
          {
            if (dirX !== 0) {
              jsp.scrollByX(dirX * settings.arrowButtonSpeed);
            }
            if (dirY !== 0) {
              jsp.scrollByY(dirY * settings.arrowButtonSpeed);
            }
            scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq);
            isFirst = false;
          };

        doScroll();

        eve = ele ? 'mouseout.jsp' : 'mouseup.jsp';
        ele = ele || $('html');
        ele.bind(
          eve,
          function()
          {
            arrow.removeClass('jspActive');
            scrollTimeout && clearTimeout(scrollTimeout);
            scrollTimeout = null;
            ele.unbind(eve);
          }
        );
      }

      function initClickOnTrack()
      {
        removeClickOnTrack();
        if (isScrollableV) {
          verticalTrack.bind(
            'mousedown.jsp',
            function(e)
            {
              if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
                var clickedTrack = $(this),
                  offset = clickedTrack.offset(),
                  direction = e.pageY - offset.top - verticalDragPosition,
                  scrollTimeout,
                  isFirst = true,
                  doScroll = function()
                  {
                    var offset = clickedTrack.offset(),
                      pos = e.pageY - offset.top - verticalDragHeight / 2,
                      contentDragY = paneHeight * settings.scrollPagePercent,
                      dragY = dragMaxY * contentDragY / (contentHeight - paneHeight);
                    if (direction < 0) {
                      if (verticalDragPosition - dragY > pos) {
                        jsp.scrollByY(-contentDragY);
                      } else {
                        positionDragY(pos);
                      }
                    } else if (direction > 0) {
                      if (verticalDragPosition + dragY < pos) {
                        jsp.scrollByY(contentDragY);
                      } else {
                        positionDragY(pos);
                      }
                    } else {
                      cancelClick();
                      return;
                    }
                    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
                    isFirst = false;
                  },
                  cancelClick = function()
                  {
                    scrollTimeout && clearTimeout(scrollTimeout);
                    scrollTimeout = null;
                    $(document).unbind('mouseup.jsp', cancelClick);
                  };
                doScroll();
                $(document).bind('mouseup.jsp', cancelClick);
                return false;
              }
            }
          );
        }
        
        if (isScrollableH) {
          horizontalTrack.bind(
            'mousedown.jsp',
            function(e)
            {
              if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
                var clickedTrack = $(this),
                  offset = clickedTrack.offset(),
                  direction = e.pageX - offset.left - horizontalDragPosition,
                  scrollTimeout,
                  isFirst = true,
                  doScroll = function()
                  {
                    var offset = clickedTrack.offset(),
                      pos = e.pageX - offset.left - horizontalDragWidth / 2,
                      contentDragX = paneWidth * settings.scrollPagePercent,
                      dragX = dragMaxX * contentDragX / (contentWidth - paneWidth);
                    if (direction < 0) {
                      if (horizontalDragPosition - dragX > pos) {
                        jsp.scrollByX(-contentDragX);
                      } else {
                        positionDragX(pos);
                      }
                    } else if (direction > 0) {
                      if (horizontalDragPosition + dragX < pos) {
                        jsp.scrollByX(contentDragX);
                      } else {
                        positionDragX(pos);
                      }
                    } else {
                      cancelClick();
                      return;
                    }
                    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
                    isFirst = false;
                  },
                  cancelClick = function()
                  {
                    scrollTimeout && clearTimeout(scrollTimeout);
                    scrollTimeout = null;
                    $(document).unbind('mouseup.jsp', cancelClick);
                  };
                doScroll();
                $(document).bind('mouseup.jsp', cancelClick);
                return false;
              }
            }
          );
        }
      }

      function removeClickOnTrack()
      {
        if (horizontalTrack) {
          horizontalTrack.unbind('mousedown.jsp');
        }
        if (verticalTrack) {
          verticalTrack.unbind('mousedown.jsp');
        }
      }

      function cancelDrag()
      {
        $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp');

        if (verticalDrag) {
          verticalDrag.removeClass('jspActive');
        }
        if (horizontalDrag) {
          horizontalDrag.removeClass('jspActive');
        }
      }

      function positionDragY(destY, animate)
      {
        if (!isScrollableV) {
          return;
        }
        if (destY < 0) {
          destY = 0;
        } else if (destY > dragMaxY) {
          destY = dragMaxY;
        }

        // can't just check if(animate) because false is a valid value that could be passed in...
        if (animate === undefined) {
          animate = settings.animateScroll;
        }
        if (animate) {
          jsp.animate(verticalDrag, 'top', destY, _positionDragY);
        } else {
          verticalDrag.css('top', destY);
          _positionDragY(destY);
        }

      }

      function _positionDragY(destY)
      {
        if (destY === undefined) {
          destY = verticalDrag.position().top;
        }

        container.scrollTop(0);
        verticalDragPosition = destY;

        var isAtTop = verticalDragPosition === 0,
          isAtBottom = verticalDragPosition == dragMaxY,
          percentScrolled = destY/ dragMaxY,
          destTop = -percentScrolled * (contentHeight - paneHeight);

        if (wasAtTop != isAtTop || wasAtBottom != isAtBottom) {
          wasAtTop = isAtTop;
          wasAtBottom = isAtBottom;
          elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
        }
        
        updateVerticalArrows(isAtTop, isAtBottom);
        pane.css('top', destTop);
        elem.trigger('jsp-scroll-y', [-destTop, isAtTop, isAtBottom]).trigger('scroll');
      }

      function positionDragX(destX, animate)
      {
        if (!isScrollableH) {
          return;
        }
        if (destX < 0) {
          destX = 0;
        } else if (destX > dragMaxX) {
          destX = dragMaxX;
        }

        if (animate === undefined) {
          animate = settings.animateScroll;
        }
        if (animate) {
          jsp.animate(horizontalDrag, 'left', destX,  _positionDragX);
        } else {
          horizontalDrag.css('left', destX);
          _positionDragX(destX);
        }
      }

      function _positionDragX(destX)
      {
        if (destX === undefined) {
          destX = horizontalDrag.position().left;
        }

        container.scrollTop(0);
        horizontalDragPosition = destX;

        var isAtLeft = horizontalDragPosition === 0,
          isAtRight = horizontalDragPosition == dragMaxX,
          percentScrolled = destX / dragMaxX,
          destLeft = -percentScrolled * (contentWidth - paneWidth);

        if (wasAtLeft != isAtLeft || wasAtRight != isAtRight) {
          wasAtLeft = isAtLeft;
          wasAtRight = isAtRight;
          elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
        }
        
        updateHorizontalArrows(isAtLeft, isAtRight);
        pane.css('left', destLeft);
        elem.trigger('jsp-scroll-x', [-destLeft, isAtLeft, isAtRight]).trigger('scroll');
      }

      function updateVerticalArrows(isAtTop, isAtBottom)
      {
        if (settings.showArrows) {
          arrowUp[isAtTop ? 'addClass' : 'removeClass']('jspDisabled');
          arrowDown[isAtBottom ? 'addClass' : 'removeClass']('jspDisabled');
        }
      }

      function updateHorizontalArrows(isAtLeft, isAtRight)
      {
        if (settings.showArrows) {
          arrowLeft[isAtLeft ? 'addClass' : 'removeClass']('jspDisabled');
          arrowRight[isAtRight ? 'addClass' : 'removeClass']('jspDisabled');
        }
      }

      function scrollToY(destY, animate)
      {
        var percentScrolled = destY / (contentHeight - paneHeight);
        positionDragY(percentScrolled * dragMaxY, animate);
      }

      function scrollToX(destX, animate)
      {
        var percentScrolled = destX / (contentWidth - paneWidth);
        positionDragX(percentScrolled * dragMaxX, animate);
      }

      function scrollToElement(ele, stickToTop, animate)
      {
        var e, eleHeight, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX;

        // Legal hash values aren't necessarily legal jQuery selectors so we need to catch any
        // errors from the lookup...
        try {
          e = $(ele);
        } catch (err) {
          return;
        }
        eleHeight = e.outerHeight();
        eleWidth= e.outerWidth();

        container.scrollTop(0);
        container.scrollLeft(0);
        
        // loop through parents adding the offset top of any elements that are relatively positioned between
        // the focused element and the jspPane so we can get the true distance from the top
        // of the focused element to the top of the scrollpane...
        while (!e.is('.jspPane')) {
          eleTop += e.position().top;
          eleLeft += e.position().left;
          e = e.offsetParent();
          if (/^body|html$/i.test(e[0].nodeName)) {
            // we ended up too high in the document structure. Quit!
            return;
          }
        }

        viewportTop = contentPositionY();
        maxVisibleEleTop = viewportTop + paneHeight;
        if (eleTop < viewportTop || stickToTop) { // element is above viewport
          destY = eleTop - settings.verticalGutter;
        } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport
          destY = eleTop - paneHeight + eleHeight + settings.verticalGutter;
        }
        if (destY) {
          scrollToY(destY, animate);
        }
        
        viewportLeft = contentPositionX();
              maxVisibleEleLeft = viewportLeft + paneWidth;
              if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport
                  destX = eleLeft - settings.horizontalGutter;
              } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport
                  destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter;
              }
              if (destX) {
                  scrollToX(destX, animate);
              }

      }

      function contentPositionX()
      {
        return -pane.position().left;
      }

      function contentPositionY()
      {
        return -pane.position().top;
      }

      function isCloseToBottom()
      {
        var scrollableHeight = contentHeight - paneHeight;
        return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10);
      }

      function isCloseToRight()
      {
        var scrollableWidth = contentWidth - paneWidth;
        return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10);
      }

      function initMousewheel()
      {
        container.unbind(mwEvent).bind(
          mwEvent,
          function (event, delta, deltaX, deltaY) {
            var dX = horizontalDragPosition, dY = verticalDragPosition;
            jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -deltaY * settings.mouseWheelSpeed, false);
            // return true if there was no movement so rest of screen can scroll
            return dX == horizontalDragPosition && dY == verticalDragPosition;
          }
        );
      }

      function removeMousewheel()
      {
        container.unbind(mwEvent);
      }

      function nil()
      {
        return false;
      }

      function initFocusHandler()
      {
        pane.find(':input,a').unbind('focus.jsp').bind(
          'focus.jsp',
          function(e)
          {
            scrollToElement(e.target, false);
          }
        );
      }

      function removeFocusHandler()
      {
        pane.find(':input,a').unbind('focus.jsp');
      }
      
      function initKeyboardNav()
      {
        var keyDown, elementHasScrolled, validParents = [];
        isScrollableH && validParents.push(horizontalBar[0]);
        isScrollableV && validParents.push(verticalBar[0]);
        
        // IE also focuses elements that don't have tabindex set.
        pane.focus(
          function()
          {
            elem.focus();
          }
        );
        
        elem.attr('tabindex', 0)
          .unbind('keydown.jsp keypress.jsp')
          .bind(
            'keydown.jsp',
            function(e)
            {
              if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){
                return;
              }
              var dX = horizontalDragPosition, dY = verticalDragPosition;
              switch(e.keyCode) {
                case 40: // down
                case 38: // up
                case 34: // page down
                case 32: // space
                case 33: // page up
                case 39: // right
                case 37: // left
                  keyDown = e.keyCode;
                  keyDownHandler();
                  break;
                case 35: // end
                  scrollToY(contentHeight - paneHeight);
                  keyDown = null;
                  break;
                case 36: // home
                  scrollToY(0);
                  keyDown = null;
                  break;
              }

              elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition;
              return !elementHasScrolled;
            }
          ).bind(
            'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls...
            function(e)
            {
              if (e.keyCode == keyDown) {
                keyDownHandler();
              }
              return !elementHasScrolled;
            }
          );
        
        if (settings.hideFocus) {
          elem.css('outline', 'none');
          if ('hideFocus' in container[0]){
            elem.attr('hideFocus', true);
          }
        } else {
          elem.css('outline', '');
          if ('hideFocus' in container[0]){
            elem.attr('hideFocus', false);
          }
        }
        
        function keyDownHandler()
        {
          var dX = horizontalDragPosition, dY = verticalDragPosition;
          switch(keyDown) {
            case 40: // down
              jsp.scrollByY(settings.keyboardSpeed, false);
              break;
            case 38: // up
              jsp.scrollByY(-settings.keyboardSpeed, false);
              break;
            case 34: // page down
            case 32: // space
              jsp.scrollByY(paneHeight * settings.scrollPagePercent, false);
              break;
            case 33: // page up
              jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false);
              break;
            case 39: // right
              jsp.scrollByX(settings.keyboardSpeed, false);
              break;
            case 37: // left
              jsp.scrollByX(-settings.keyboardSpeed, false);
              break;
          }

          elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition;
          return elementHasScrolled;
        }
      }
      
      function removeKeyboardNav()
      {
        elem.attr('tabindex', '-1')
          .removeAttr('tabindex')
          .unbind('keydown.jsp keypress.jsp');
      }

      function observeHash()
      {
        if (location.hash && location.hash.length > 1) {
          var e,
            retryInt,
            hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS
            ;
          try {
            e = $('#' + hash + ', a[name="' + hash + '"]');
          } catch (err) {
            return;
          }

          if (e.length && pane.find(hash)) {
            // nasty workaround but it appears to take a little while before the hash has done its thing
            // to the rendered page so we just wait until the container's scrollTop has been messed up.
            if (container.scrollTop() === 0) {
              retryInt = setInterval(
                function()
                {
                  if (container.scrollTop() > 0) {
                    scrollToElement(e, true);
                    $(document).scrollTop(container.position().top);
                    clearInterval(retryInt);
                  }
                },
                50
              );
            } else {
              scrollToElement(e, true);
              $(document).scrollTop(container.position().top);
            }
          }
        }
      }

      function hijackInternalLinks()
      {
        // only register the link handler once
        if ($(document.body).data('jspHijack')) {
          return;
        }

        // remember that the handler was bound
        $(document.body).data('jspHijack', true);

        // use live handler to also capture newly created links
        $(document.body).delegate('a[href*=#]', 'click', function(event) {
          // does the link point to the same page?
          // this also takes care of cases with a <base>-Tag or Links not starting with the hash #
          // e.g. <a href="index.html#test"> when the current url already is index.html
          var href = this.href.substr(0, this.href.indexOf('#')),
            locationHref = location.href,
            hash,
            element,
            container,
            jsp,
            scrollTop,
            elementTop;
          if (location.href.indexOf('#') !== -1) {
            locationHref = location.href.substr(0, location.href.indexOf('#'));
          }
          if (href !== locationHref) {
            // the link points to another page
            return;
          }

          // check if jScrollPane should handle this click event
          hash = escape(this.href.substr(this.href.indexOf('#') + 1));

          // find the element on the page
          element;
          try {
            element = $('#' + hash + ', a[name="' + hash + '"]');
          } catch (e) {
            // hash is not a valid jQuery identifier
            return;
          }

          if (!element.length) {
            // this link does not point to an element on this page
            return;
          }

          container = element.closest('.jspScrollable');
          jsp = container.data('jsp');

          // jsp might be another jsp instance than the one, that bound this event
          // remember: this event is only bound once for all instances.
          jsp.scrollToElement(element, true);

          if (container[0].scrollIntoView) {
            // also scroll to the top of the container (if it is not visible)
            scrollTop = $(window).scrollTop();
            elementTop = element.offset().top;
            if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) {
              container[0].scrollIntoView();
            }
          }

          // jsp handled this event, prevent the browser default (scrolling :P)
          event.preventDefault();
        });
      }
      
      // Init touch on iPad, iPhone, iPod, Android
      function initTouch()
      {
        var startX,
          startY,
          touchStartX,
          touchStartY,
          moved,
          moving = false;
  
        container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind(
          'touchstart.jsp',
          function(e)
          {
            var touch = e.originalEvent.touches[0];
            startX = contentPositionX();
            startY = contentPositionY();
            touchStartX = touch.pageX;
            touchStartY = touch.pageY;
            moved = false;
            moving = true;
          }
        ).bind(
          'touchmove.jsp',
          function(ev)
          {
            if(!moving) {
              return;
            }
            
            var touchPos = ev.originalEvent.touches[0],
              dX = horizontalDragPosition, dY = verticalDragPosition;
            
            jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY);
            
            moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5;
            
            // return true if there was no movement so rest of screen can scroll
            return dX == horizontalDragPosition && dY == verticalDragPosition;
          }
        ).bind(
          'touchend.jsp',
          function(e)
          {
            moving = false;
            /*if(moved) {
              return false;
            }*/
          }
        ).bind(
          'click.jsp-touchclick',
          function(e)
          {
            if(moved) {
              moved = false;
              return false;
            }
          }
        );
      }
      
      function destroy(){
        var currentY = contentPositionY(),
          currentX = contentPositionX();
        elem.removeClass('jspScrollable').unbind('.jsp');
        elem.replaceWith(originalElement.append(pane.children()));
        originalElement.scrollTop(currentY);
        originalElement.scrollLeft(currentX);

        // clear reinitialize timer if active
        if (reinitialiseInterval) {
          clearInterval(reinitialiseInterval);
        }
      }

      // Public API
      $.extend(
        jsp,
        {
          // Reinitialises the scroll pane (if it's internal dimensions have changed since the last time it
          // was initialised). The settings object which is passed in will override any settings from the
          // previous time it was initialised - if you don't pass any settings then the ones from the previous
          // initialisation will be used.
          reinitialise: function(s)
          {
            s = $.extend({}, settings, s);
            initialise(s);
          },
          // Scrolls the specified element (a jQuery object, DOM node or jQuery selector string) into view so
          // that it can be seen within the viewport. If stickToTop is true then the element will appear at
          // the top of the viewport, if it is false then the viewport will scroll as little as possible to
          // show the element. You can also specify if you want animation to occur. If you don't provide this
          // argument then the animateScroll value from the settings object is used instead.
          scrollToElement: function(ele, stickToTop, animate)
          {
            scrollToElement(ele, stickToTop, animate);
          },
          // Scrolls the pane so that the specified co-ordinates within the content are at the top left
          // of the viewport. animate is optional and if not passed then the value of animateScroll from
          // the settings object this jScrollPane was initialised with is used.
          scrollTo: function(destX, destY, animate)
          {
            scrollToX(destX, animate);
            scrollToY(destY, animate);
          },
          // Scrolls the pane so that the specified co-ordinate within the content is at the left of the
          // viewport. animate is optional and if not passed then the value of animateScroll from the settings
          // object this jScrollPane was initialised with is used.
          scrollToX: function(destX, animate)
          {
            scrollToX(destX, animate);
          },
          // Scrolls the pane so that the specified co-ordinate within the content is at the top of the
          // viewport. animate is optional and if not passed then the value of animateScroll from the settings
          // object this jScrollPane was initialised with is used.
          scrollToY: function(destY, animate)
          {
            scrollToY(destY, animate);
          },
          // Scrolls the pane to the specified percentage of its maximum horizontal scroll position. animate
          // is optional and if not passed then the value of animateScroll from the settings object this
          // jScrollPane was initialised with is used.
          scrollToPercentX: function(destPercentX, animate)
          {
            scrollToX(destPercentX * (contentWidth - paneWidth), animate);
          },
          // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate
          // is optional and if not passed then the value of animateScroll from the settings object this
          // jScrollPane was initialised with is used.
          scrollToPercentY: function(destPercentY, animate)
          {
            scrollToY(destPercentY * (contentHeight - paneHeight), animate);
          },
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
          scrollBy: function(deltaX, deltaY, animate)
          {
            jsp.scrollByX(deltaX, animate);
            jsp.scrollByY(deltaY, animate);
          },
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
          scrollByX: function(deltaX, animate)
          {
            var destX = contentPositionX() + Math[deltaX<0 ? 'floor' : 'ceil'](deltaX),
              percentScrolled = destX / (contentWidth - paneWidth);
            positionDragX(percentScrolled * dragMaxX, animate);
          },
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
          scrollByY: function(deltaY, animate)
          {
            var destY = contentPositionY() + Math[deltaY<0 ? 'floor' : 'ceil'](deltaY),
              percentScrolled = destY / (contentHeight - paneHeight);
            positionDragY(percentScrolled * dragMaxY, animate);
          },
          // Positions the horizontal drag at the specified x position (and updates the viewport to reflect
          // this). animate is optional and if not passed then the value of animateScroll from the settings
          // object this jScrollPane was initialised with is used.
          positionDragX: function(x, animate)
          {
            positionDragX(x, animate);
          },
          // Positions the vertical drag at the specified y position (and updates the viewport to reflect
          // this). animate is optional and if not passed then the value of animateScroll from the settings
          // object this jScrollPane was initialised with is used.
          positionDragY: function(y, animate)
          {
            positionDragY(y, animate);
          },
          // This method is called when jScrollPane is trying to animate to a new position. You can override
          // it if you want to provide advanced animation functionality. It is passed the following arguments:
          //  * ele          - the element whose position is being animated
          //  * prop         - the property that is being animated
          //  * value        - the value it's being animated to
          //  * stepCallback - a function that you must execute each time you update the value of the property
          // You can use the default implementation (below) as a starting point for your own implementation.
          animate: function(ele, prop, value, stepCallback)
          {
            var params = {};
            params[prop] = value;
            ele.animate(
              params,
              {
                'duration'  : settings.animateDuration,
                'easing'  : settings.animateEase,
                'queue'   : false,
                'step'    : stepCallback
              }
            );
          },
          // Returns the current x position of the viewport with regards to the content pane.
          getContentPositionX: function()
          {
            return contentPositionX();
          },
          // Returns the current y position of the viewport with regards to the content pane.
          getContentPositionY: function()
          {
            return contentPositionY();
          },
          // Returns the width of the content within the scroll pane.
          getContentWidth: function()
          {
            return contentWidth;
          },
          // Returns the height of the content within the scroll pane.
          getContentHeight: function()
          {
            return contentHeight;
          },
          // Returns the horizontal position of the viewport within the pane content.
          getPercentScrolledX: function()
          {
            return contentPositionX() / (contentWidth - paneWidth);
          },
          // Returns the vertical position of the viewport within the pane content.
          getPercentScrolledY: function()
          {
            return contentPositionY() / (contentHeight - paneHeight);
          },
          // Returns whether or not this scrollpane has a horizontal scrollbar.
          getIsScrollableH: function()
          {
            return isScrollableH;
          },
          // Returns whether or not this scrollpane has a vertical scrollbar.
          getIsScrollableV: function()
          {
            return isScrollableV;
          },
          // Gets a reference to the content pane. It is important that you use this method if you want to
          // edit the content of your jScrollPane as if you access the element directly then you may have some
          // problems (as your original element has had additional elements for the scrollbars etc added into
          // it).
          getContentPane: function()
          {
            return pane;
          },
          // Scrolls this jScrollPane down as far as it can currently scroll. If animate isn't passed then the
          // animateScroll value from settings is used instead.
          scrollToBottom: function(animate)
          {
            positionDragY(dragMaxY, animate);
          },
          // Hijacks the links on the page which link to content inside the scrollpane. If you have changed
          // the content of your page (e.g. via AJAX) and want to make sure any new anchor links to the
          // contents of your scroll pane will work then call this function.
          hijackInternalLinks: $.noop,
          // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was
          // initialised.
          destroy: function()
          {
              destroy();
          }
        }
      );
      
      initialise(s);
    }
517254
function scrollToIndex(index) {
    var duration = 400;
    var start = window.pageYOffset;
    var end = index * window.innerHeight;
    var amount = end - start;
    var startTime = +new Date();

    var easing = function easing(k) {
      return -0.5 * (Math.cos(Math.PI * k) - 1);
    };

    var step = function step(value /* , percent */) {
      window.scrollTo(0, value);
    };

    var complete = function complete() {
      isScrolling = false;
    };

    var looper = function looper() {
      var now = +new Date();
      var remainingTime = startTime + duration - now;
      var percent = 1 - (remainingTime / duration || 0);

      // Abort if already past 100%.
      if (percent >= 1) {
        // Make sure it always finishes with 1.
        step(end, 1);
        complete();
        return;
      }

      // Apply easing.
      percent = easing(percent);

      // Tick.
      step(start + amount * percent, percent);

      // Request animation frame.
      requestAnimationFrame(looper);
    };

    isScrolling = true;
    requestAnimationFrame(looper);
  }
476859
function Scrollify(element) {
  var this$1 = this;

  if (element instanceof HTMLElement == false) { element = document.querySelector(element); }
  if (!element || !transform) {
    console.log('Scrollify [error] ', arguments[0]);
    return this.disable();
  }

  this.element = element;
  this.ticking = false;
  this.scenes = [];
  this.scroll = window.scrollY || window.pageYOffset;
  this.active = true;
  this.matrix = createMatrix();
  this.transforms = {
    scale: [1,1],
    rotation: [0,0,0],
    position: [0,0,0],
    // transformOrigin: [0,0,0]
    // skew: [],
  };

  window.addEventListener('scroll', function () { return this$1.onScroll(); }, { passive: true });
  window.addEventListener('resize', function () { return this$1.onResize(); }, { passive: true });
}
603584
function(init, recnt) {
				var firstNode = (list? cwd.find('tbody:first') : cwd).children('[id]:first');
				if (!firstNode.length) {
					return;
				}
				var selectable = cwd.data('selectable'),
					rec = (function() {
						var wos = wrapper.offset(),
							w = $(window),
							x = firstNode.width() / 2,
							l = wos.left - w.scrollLeft() + (fm.direction === 'ltr'? x : wrapper.width() - x),
							t = wos.top - w.scrollTop() + 10 + (list? bufferExt.itemH || (fm.UA.Touch? 36 : 24) : 0);
						return {left: Math.max(0, Math.round(l)), top: Math.max(0, Math.round(t))};
					})(),
					tgt = init? firstNode : $(document.elementFromPoint(rec.left , rec.top)),
					ids = {},
					tmbs = {},
					multi = 5,
					cnt = Math.ceil((bufferExt.hpi? Math.ceil((wz.data('rectangle').height / bufferExt.hpi) * 1.5) : showFiles) / multi),
					chk = function() {
						var id, hash, file, i;
						for (i = 0; i < multi; i++) {
							id = tgt.attr('id');
							if (id) {
								bufferExt.getTmbs = [];
								hash = fm.cwdId2Hash(id);
								inViewHashes[hash] = id;
								// for tmbs
								if (bufferExt.attachTmbs[hash]) {
									tmbs[hash] = bufferExt.attachTmbs[hash];
								}
								// for selectable
								selectable && (ids[id] = true);
							}
							// next node
							tgt = tgt.next();
							if (!tgt.length) {
								break;
							}
						}
					},
					done = function() {
						var idsArr;
						if (cwd.data('selectable')) {
							Object.assign(ids, selectedFiles);
							idsArr = Object.keys(ids);
							if (idsArr.length) {
								selectableOption.filter = '#'+idsArr.join(', #');
								cwd.selectable('enable').selectable('option', {filter : selectableOption.filter}).selectable('refresh');
							}
						}
						if (Object.keys(tmbs).length) {
							bufferExt.getTmbs = [];
							attachThumbnails(tmbs);
						}
					},
					setTarget = function() {
						if (!tgt.hasClass(clFile)) {
							tgt = tgt.closest(fileSelector);
						}
					},
					arr, widget;
				
				inViewHashes = {};
				selectable && cwd.selectable('option', 'disabled');
				
				if (tgt.length) {
					if (!tgt.hasClass(clFile) && !tgt.closest(fileSelector).length) {
						// dialog, serach button etc.
						widget = fm.getUI().find('.ui-dialog:visible,.ui-widget:visible');
						if (widget.length) {
							widget.hide();
							tgt = $(document.elementFromPoint(rec.left , rec.top));
							widget.show();
						} else {
							widget = null;
						}
					}
					setTarget();
					if (!tgt.length) {
						// try search 5px down
						widget && widget.hide();
						tgt = $(document.elementFromPoint(rec.left , rec.top + 5));
						widget && widget.show();
						setTarget();
					}
				}

				if (tgt.length) {
					if (tgt.attr('id')) {
						if (init) {
							for (var i = 0; i < cnt; i++) {
								chk();
								if (! tgt.length) {
									break;
								}
							}
							done();
						} else {
							bufferExt.repaintJob && bufferExt.repaintJob.state() === 'pending' && bufferExt.repaintJob.reject();
							arr = new Array(cnt);
							bufferExt.repaintJob = fm.asyncJob(function() {
								chk();
								if (! tgt.length) {
									done();
									bufferExt.repaintJob && bufferExt.repaintJob.state() === 'pending' && bufferExt.repaintJob.reject();
								}
							}, arr).done(done);
						}
					}
				} else if (init && bufferExt.renderd) {
					// In initial request, cwd DOM not renderd so doing lazy check
					recnt = recnt || 0;
					if (recnt < 10) { // Prevent infinite loop
						requestAnimationFrame(function() {
							wrapperRepaint(init, ++recnt);
						});
					}
				}
			}
823215
function scrollInterpolator4 (index, carouselProps) {
    const range = [1, 0, -1];
    const inputRange = getInputRangeFromIndexes(range, index, carouselProps);
    const outputRange = range;

    return { inputRange, outputRange };
}
186862
function sortByDepth(arr, descending) {
    arr.sort(function (a, b) {
        return dom(descending ? b : a).parents().length - dom(descending ? a : b).parents().length;
    });
}
437965
function scrollOnePage(element, downward) {

  // Determine the item visible just at the edge of direction we're heading.
  // We'll select that item if it's not already selected.
  const scrollTarget = element.scrollTarget;
  const edge = scrollTarget.scrollTop + (downward ? scrollTarget.clientHeight : 0);
  const indexOfItemAtEdge = getIndexOfItemAtY(element, edge, downward);

  const selectedIndex = element.selectedIndex;
  let newIndex;
  if (indexOfItemAtEdge && selectedIndex === indexOfItemAtEdge) {
    // The item at the edge was already selected, so scroll in the indicated
    // direction by one page. Leave the new item at that edge selected.
    const delta = (downward ? 1 : -1) * scrollTarget.clientHeight;
    newIndex = getIndexOfItemAtY(element, edge + delta, downward);
  }
  else {
    // The item at the edge wasn't selected yet. Instead of scrolling, we'll
    // just select that item. That is, the first attempt to page up/down
    // usually just moves the selection to the edge in that direction.
    newIndex = indexOfItemAtEdge;
  }

  if (!newIndex) {
    // We can't find an item in the direction we want to travel. Select the
    // last item (if moving downward) or first item (if moving upward).
    newIndex = (downward ? element.items.length - 1 : 0);
  }

  if (newIndex !== selectedIndex) {
    element.selectedIndex = newIndex;
    return true; // We handled the page up/down ourselves.
  }
  else {
    return false; // We didn't do anything.
  }
}
534412
function (collection, settings, elements, element, index) {
            if (index !== (elements.length - 1) && trueOrUndefined(settings.before_down(collection, element))) {
                elements = swapElements(collection, elements, index, index + 1);
                if (!trueOrUndefined(settings.after_down(collection, elements))) {
                    elements = swapElements(collection, elements, index + 1, index);
                }
            }

            if (settings.position_field_selector) {
                return doRewritePositions(settings, elements);
            }

            return elements;
        }
869355
def scroll_one_line_down(event):
    
    w = find_window_for_buffer_name(event.cli, event.cli.current_buffer_name)
    b = event.cli.current_buffer

    if w:
        # When the cursor is at the top, move to the next line. (Otherwise, only scroll.)
        if w.render_info:
            info = w.render_info

            if w.vertical_scroll < info.content_height - info.window_height:
                if info.cursor_position.y <= info.configured_scroll_offsets.top:
                    b.cursor_position += b.document.get_cursor_down_position()

                w.vertical_scroll += 1
80297
function (left, top) {
            left = parseInt(left, 10) || 0;
            top = parseInt(top, 10) || 0;
            this.scrollToOffset(left + this.state.scrollLeft, top + this.state.scrollTop);
        }
1154425
function offset(el) {
  const rect = el.getBoundingClientRect();
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
  const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;

  return {
    top: rect.top + scrollTop,
    left: rect.left + scrollLeft
  };
}
9691
function reverseArray(array) {
  let index = array.length,
      newArray = [];

  while (index--) {
    newArray.push(array[index]);
  }

  return newArray;
}
343210
function() {
    // Reset scroll positions
    if(this._nScrollTop) {
        this._elBdContainer.scrollTop = this._nScrollTop;
        this._nScrollTop = null;
    } 
    if(this._nScrollLeft) {
        this._elBdContainer.scrollLeft = this._nScrollLeft;
        this._nScrollLeft = null;
    } 
}
565286
function scrollToPageBottom() {
  const scrollingElement = (document.scrollingElement || document.body);
  scrollingElement.scrollTop = scrollingElement.scrollHeight;
}