<commit_before>/**
 * Note(gdh1995):
 * - All private members are @NEED_SAFE_ELEMENTS
 * - Untagged public members are @safe_even_if_any_overridden_property
 */
declare namespace ScrollerNS {
  const enum Consts {
    calibrationBoundary = 150, maxCalibration = 1.6, minCalibration = 0.5,
    minDuration = 100, durationScaleForAmount = 20,
    maxS = 1.05, minS = 0.95, delayToChangeSpeed = 75, tickForUnexpectedTime = 17, firstTick = 17,

    DelayMinDelta = 60, DelayTolerance = 60,
    DelayUnitMs = 30, FrameIntervalMs = 16.67, MaxSkippedF = 4,
    // https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc978658(v=technet.10)
    //            delay         interval  # delay - interval (not so useful)
    // high:  60f / 1000ms :  400ms / 24f # 660 / 28
    // low:   15f /  250ms :   33ms /  2f # 200 / 6
    HighDelayMs = 1000, LowDelayMs = 250, DefaultMinDelayMs = 660,
    HighIntervalF = 24, LowIntervalF = 2, DefaultMaxIntervalF = HighIntervalF + MaxSkippedF,

    AmountLimitToScrollAndWaitRepeatedKeys = 20,
  }
}
declare const enum kScrollDim {
  _mask = "",
  viewSize = 0,
  scrollSize = 1,
  position = 2,
}
interface ElementScrollInfo {
  area_: number;
  element_: SafeElement;
  height_: number; /* cropped visible */
}
var VScroller = {
_animate (e: SafeElement | null, d: ScrollByY, a: number): void {
  let amount = 0, calibration = 1.0, di: ScrollByY = 0, duration = 0, element: SafeElement | null = null, //
  sign = 0, timestamp = 0, totalDelta = 0.0, totalElapsed = 0.0, //
  running = 0 as number, next = requestAnimationFrame, timer = 0;
  function animate(newTimestamp: number): void {
    const _this = VScroller,
    // although timestamp is mono, Firefox adds too many limits to its precision
    elapsed = !timestamp ? (newTimestamp = performance.now(), ScrollerNS.Consts.firstTick)
              : newTimestamp > timestamp ? newTimestamp - timestamp
              : (newTimestamp += ScrollerNS.Consts.tickForUnexpectedTime, ScrollerNS.Consts.tickForUnexpectedTime),
    continuous = _this.keyIsDown_ > 0;
    if (!_this) { return; }
    timestamp = newTimestamp;
    totalElapsed += elapsed;
    if (amount < ScrollerNS.Consts.AmountLimitToScrollAndWaitRepeatedKeys
        && continuous && totalDelta >= amount && totalElapsed < _this.minDelay_ - 2) {
      running = 0;
      timer = setTimeout(startAnimate, _this.minDelay_ - totalElapsed);
      return;
    }
    if (continuous) {
      if (totalElapsed >= ScrollerNS.Consts.delayToChangeSpeed) {
        if (totalElapsed > _this.minDelay_) { --_this.keyIsDown_; }
        if (ScrollerNS.Consts.minCalibration <= calibration && calibration <= ScrollerNS.Consts.maxCalibration) {
          const calibrationScale = ScrollerNS.Consts.calibrationBoundary / amount / calibration;
          calibration *= calibrationScale > ScrollerNS.Consts.maxS ? ScrollerNS.Consts.maxS
            : calibrationScale < ScrollerNS.Consts.minS ? ScrollerNS.Consts.minS : 1;
        }
      }
    }
    let delta = Math.ceil(amount * (elapsed / duration) * calibration);
    continuous || (delta = Math.min(delta, amount - totalDelta));
    if (delta > 0 && _this._performScroll(element, di, sign * delta)) {
      totalDelta += delta;
      next(animate);
    } else {
      _this._checkCurrent(element);
      element = null;
      running = 0;
    }
  }
  function startAnimate(): void {
    timer = 0;
    running = running || next(animate);
  }
  this._animate = (function (this: typeof VScroller, newEl, newDi, newAmount): void {
    const M = Math;
    amount = M.abs(newAmount); calibration = 1.0; di = newDi;
    duration = M.max(ScrollerNS.Consts.minDuration, ScrollerNS.Consts.durationScaleForAmount * M.log(amount));
    element = newEl;
    sign = newAmount < 0 ? -1 : 1;
    totalDelta = totalElapsed = 0.0;
    timestamp = 0;
    if (timer) {
      clearTimeout(timer);
    }
    const keyboard = VDom.cache_.keyboard;
    this.maxInterval_ = M.round(keyboard[1] / ScrollerNS.Consts.FrameIntervalMs) + ScrollerNS.Consts.MaxSkippedF;
    this.minDelay_ = (((keyboard[0] + M.max(keyboard[1], ScrollerNS.Consts.DelayMinDelta)
          + ScrollerNS.Consts.DelayTolerance) / ScrollerNS.Consts.DelayUnitMs) | 0)
      * ScrollerNS.Consts.DelayUnitMs;
    this.scrollTick_(1);
    startAnimate();
  });
  return this._animate(e, d, a);
},
  maxInterval_: ScrollerNS.Consts.DefaultMaxIntervalF as number,
  minDelay_: ScrollerNS.Consts.DefaultMinDelayMs as number,
  _performScroll (el: SafeElement | null, di: ScrollByY, amount: number, before?: number): boolean {
    if (di) {
      if (el) {
        before = before == null ? el.scrollTop : before;
        !(Build.BTypes & BrowserType.Edge) && Build.MinCVer >= BrowserVer.MinEnsuredCSS$ScrollBehavior ||
        !(Build.BTypes & ~BrowserType.Firefox) ||
        el.scrollBy ? el.scrollBy({behavior: "instant", top: amount}) : (el.scrollTop += amount);
        return el.scrollTop !== before;
      } else {
        before = scrollY;
        // avoid using `Element`, so that users may override it
        VDom.scrollWndBy_(0, amount);
        return scrollY !== before;
      }
    } else if (el) {
      before = before == null ? el.scrollTop : before;
      !(Build.BTypes & BrowserType.Edge) && Build.MinCVer >= BrowserVer.MinEnsuredCSS$ScrollBehavior ||
      !(Build.BTypes & ~BrowserType.Firefox) ||
      el.scrollBy ? el.scrollBy({behavior: "instant", left: amount}) : (el.scrollLeft += amount);
      return el.scrollLeft !== before;
    } else {
      before = scrollX;
      VDom.scrollWndBy_(amount, 0);
      return scrollX !== before;
    }
  },
  _innerScroll (element: SafeElement | null, di: ScrollByY, amount: number): void | number | boolean {
    if (!amount) { return; }
    if (VDom.cache_.smoothScroll
        && (Build.MinCVer > BrowserVer.NoRAFOrRICOnSandboxedPage || !(Build.BTypes & BrowserType.Chrome)
            || VDom.allowRAF_)) {
      this._animate(element, di, amount);
    } else {
      this._performScroll(element, di, amount);
      this._checkCurrent(element);
    }
  },

  /** @NEED_SAFE_ELEMENTS */
  current_: null as SafeElement | null,
  /** @NEED_SAFE_ELEMENTS */
  top_: null as SafeElement | null,
  keyIsDown_: 0,
  scale_: 1,
  activate_ (this: void, count: number, options: CmdOptions[kFgCmd.scroll] & SafeObject): void {
    if (VEvent.checkHidden_(kFgCmd.scroll, count, options)) { return; }
    if (VHints.TryNestedFrame_(kFgCmd.scroll, count, options)) { return; }
    const a = VScroller, di: ScrollByY = options.axis === "x" ? 0 : 1,
    dest = options.dest;
    let fromMax = dest === "max";
    if (dest) {
      if (count < 0) { fromMax = !fromMax; count = -count; }
      count--;
    } else {
      count *= +<number> options.dir || 1;
    }
    return a.scroll_(di, count, dest ? 1 as never : 0, options.view, fromMax as false);
  },
  /**
   * @param amount0 can not be 0, if `isTo` is 0
   * @param factor `!!factor` can be true only if `isTo` is 0
   * @param fromMax can not be true, if `isTo` is 0
   */
  scroll_: function (this: {}, di: ScrollByY, amount0: number, isTo: BOOL
      , factor?: NonNullable<CmdOptions[kFgCmd.scroll]["view"]> | undefined, fromMax?: boolean): void {
    const a = this as typeof VScroller;
    a.prepareTop_();
    isTo && di && VMarks.setPreviousPosition_();
    let amount = amount0;
    const element = a.findScrollable_(di, isTo ? fromMax ? 1 : -1 : amount);
    amount = !factor ? a._adjustAmount(di, amount, element)
      : factor === 1 ? amount
      : amount * a.getDimension_(element, di, factor === "max" ? kScrollDim.scrollSize : kScrollDim.viewSize);
    if (fromMax) {
      amount = a.getDimension_(element, di, kScrollDim.scrollSize) - amount
        - a.getDimension_(element, di, kScrollDim.viewSize);
    }
    if (isTo) {
      amount -= element ? a.getDimension_(element, di, kScrollDim.position) : di ? scrollY : scrollX;
    }
    if (amount && element === a.top_ && element && window !== top && VDom.parentFrame_()) {
      // somehow like https://github.com/philc/vimium/pull/2875
      interface VWindow extends Window {
        VDom: typeof VDom;
        VScroller: typeof VScroller;
      }
      const par = parent, Sc = par && (par as VWindow).VScroller;<commit_msg>noop: VScroller: finish the feature of auto-upper-frame<commit_after>/**
 * Note(gdh1995):
 * - All private members are @NEED_SAFE_ELEMENTS
 * - Untagged public members are @safe_even_if_any_overridden_property
 */
declare namespace ScrollerNS {
  const enum Consts {
    calibrationBoundary = 150, maxCalibration = 1.6, minCalibration = 0.5,
    minDuration = 100, durationScaleForAmount = 20,
    maxS = 1.05, minS = 0.95, delayToChangeSpeed = 75, tickForUnexpectedTime = 17, firstTick = 17,

    DelayMinDelta = 60, DelayTolerance = 60,
    DelayUnitMs = 30, FrameIntervalMs = 16.67, MaxSkippedF = 4,
    // https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc978658(v=technet.10)
    //            delay         interval  # delay - interval (not so useful)
    // high:  60f / 1000ms :  400ms / 24f # 660 / 28
    // low:   15f /  250ms :   33ms /  2f # 200 / 6
    HighDelayMs = 1000, LowDelayMs = 250, DefaultMinDelayMs = 660,
    HighIntervalF = 24, LowIntervalF = 2, DefaultMaxIntervalF = HighIntervalF + MaxSkippedF,

    AmountLimitToScrollAndWaitRepeatedKeys = 20,
  }
}
declare const enum kScrollDim {
  _mask = "",
  viewSize = 0,
  scrollSize = 1,
  position = 2,
}
interface ElementScrollInfo {
  area_: number;
  element_: SafeElement;
  height_: number; /* cropped visible */
}
var VScroller = {
_animate (e: SafeElement | null, d: ScrollByY, a: number): void {
  let amount = 0, calibration = 1.0, di: ScrollByY = 0, duration = 0, element: SafeElement | null = null, //
  sign = 0, timestamp = 0, totalDelta = 0.0, totalElapsed = 0.0, //
  running = 0 as number, next = requestAnimationFrame, timer = 0;
  function animate(newTimestamp: number): void {
    const _this = VScroller,
    // although timestamp is mono, Firefox adds too many limits to its precision
    elapsed = !timestamp ? (newTimestamp = performance.now(), ScrollerNS.Consts.firstTick)
              : newTimestamp > timestamp ? newTimestamp - timestamp
              : (newTimestamp += ScrollerNS.Consts.tickForUnexpectedTime, ScrollerNS.Consts.tickForUnexpectedTime),
    continuous = _this.keyIsDown_ > 0;
    if (!_this) { return; }
    timestamp = newTimestamp;
    totalElapsed += elapsed;
    if (amount < ScrollerNS.Consts.AmountLimitToScrollAndWaitRepeatedKeys
        && continuous && totalDelta >= amount && totalElapsed < _this.minDelay_ - 2) {
      running = 0;
      timer = setTimeout(startAnimate, _this.minDelay_ - totalElapsed);
      return;
    }
    if (continuous) {
      if (totalElapsed >= ScrollerNS.Consts.delayToChangeSpeed) {
        if (totalElapsed > _this.minDelay_) { --_this.keyIsDown_; }
        if (ScrollerNS.Consts.minCalibration <= calibration && calibration <= ScrollerNS.Consts.maxCalibration) {
          const calibrationScale = ScrollerNS.Consts.calibrationBoundary / amount / calibration;
          calibration *= calibrationScale > ScrollerNS.Consts.maxS ? ScrollerNS.Consts.maxS
            : calibrationScale < ScrollerNS.Consts.minS ? ScrollerNS.Consts.minS : 1;
        }
      }
    }
    let delta = Math.ceil(amount * (elapsed / duration) * calibration);
    continuous || (delta = Math.min(delta, amount - totalDelta));
    if (delta > 0 && _this._performScroll(element, di, sign * delta)) {
      totalDelta += delta;
      next(animate);
    } else {
      _this._checkCurrent(element);
      element = null;
      running = 0;
    }
  }
  function startAnimate(): void {
    timer = 0;
    running = running || next(animate);
  }
  this._animate = (function (this: typeof VScroller, newEl, newDi, newAmount): void {
    const M = Math;
    amount = M.abs(newAmount); calibration = 1.0; di = newDi;
    duration = M.max(ScrollerNS.Consts.minDuration, ScrollerNS.Consts.durationScaleForAmount * M.log(amount));
    element = newEl;
    sign = newAmount < 0 ? -1 : 1;
    totalDelta = totalElapsed = 0.0;
    timestamp = 0;
    if (timer) {
      clearTimeout(timer);
    }
    const keyboard = VDom.cache_.keyboard;
    this.maxInterval_ = M.round(keyboard[1] / ScrollerNS.Consts.FrameIntervalMs) + ScrollerNS.Consts.MaxSkippedF;
    this.minDelay_ = (((keyboard[0] + M.max(keyboard[1], ScrollerNS.Consts.DelayMinDelta)
          + ScrollerNS.Consts.DelayTolerance) / ScrollerNS.Consts.DelayUnitMs) | 0)
      * ScrollerNS.Consts.DelayUnitMs;
    this.scrollTick_(1);
    startAnimate();
  });
  return this._animate(e, d, a);
},
  maxInterval_: ScrollerNS.Consts.DefaultMaxIntervalF as number,
  minDelay_: ScrollerNS.Consts.DefaultMinDelayMs as number,
  _performScroll (el: SafeElement | null, di: ScrollByY, amount: number, before?: number): boolean {
    if (di) {
      if (el) {
        before = before == null ? el.scrollTop : before;
        !(Build.BTypes & BrowserType.Edge) && Build.MinCVer >= BrowserVer.MinEnsuredCSS$ScrollBehavior ||
        !(Build.BTypes & ~BrowserType.Firefox) ||
        el.scrollBy ? el.scrollBy({behavior: "instant", top: amount}) : (el.scrollTop += amount);
        return el.scrollTop !== before;
      } else {
        before = scrollY;
        // avoid using `Element`, so that users may override it
        VDom.scrollWndBy_(0, amount);
        return scrollY !== before;
      }
    } else if (el) {
      before = before == null ? el.scrollTop : before;
      !(Build.BTypes & BrowserType.Edge) && Build.MinCVer >= BrowserVer.MinEnsuredCSS$ScrollBehavior ||
      !(Build.BTypes & ~BrowserType.Firefox) ||
      el.scrollBy ? el.scrollBy({behavior: "instant", left: amount}) : (el.scrollLeft += amount);
      return el.scrollLeft !== before;
    } else {
      before = scrollX;
      VDom.scrollWndBy_(amount, 0);
      return scrollX !== before;
    }
  },
  _innerScroll (element: SafeElement | null, di: ScrollByY, amount: number): void | number | boolean {
    if (!amount) { return; }
    if (VDom.cache_.smoothScroll
        && (Build.MinCVer > BrowserVer.NoRAFOrRICOnSandboxedPage || !(Build.BTypes & BrowserType.Chrome)
            || VDom.allowRAF_)) {
      this._animate(element, di, amount);
    } else {
      this._performScroll(element, di, amount);
      this._checkCurrent(element);
    }
  },

  /** @NEED_SAFE_ELEMENTS */
  current_: null as SafeElement | null,
  /** @NEED_SAFE_ELEMENTS */
  top_: null as SafeElement | null,
  keyIsDown_: 0,
  scale_: 1,
  activate_ (this: void, count: number, options: CmdOptions[kFgCmd.scroll] & SafeObject): void {
    if (VEvent.checkHidden_(kFgCmd.scroll, count, options)) { return; }
    if (VHints.TryNestedFrame_(kFgCmd.scroll, count, options)) { return; }
    const a = VScroller, di: ScrollByY = options.axis === "x" ? 0 : 1,
    dest = options.dest;
    let fromMax = dest === "max";
    if (dest) {
      if (count < 0) { fromMax = !fromMax; count = -count; }
      count--;
    } else {
      count *= +<number> options.dir || 1;
    }
    return a.scroll_(di, count, dest ? 1 as never : 0, options.view, fromMax as false);
  },
  /**
   * @param amount0 can not be 0, if `isTo` is 0
   * @param factor `!!factor` can be true only if `isTo` is 0
   * @param fromMax can not be true, if `isTo` is 0
   */
  scroll_: function (this: {}, di: ScrollByY, amount0: number, isTo: BOOL
      , factor?: NonNullable<CmdOptions[kFgCmd.scroll]["view"]> | undefined, fromMax?: boolean): void {
    const a = this as typeof VScroller;
    a.prepareTop_();
    isTo && di && VMarks.setPreviousPosition_();
    let amount = amount0;
    const element = a.findScrollable_(di, isTo ? fromMax ? 1 : -1 : amount);
    amount = !factor ? a._adjustAmount(di, amount, element)
      : factor === 1 ? amount
      : amount * a.getDimension_(element, di, factor === "max" ? kScrollDim.scrollSize : kScrollDim.viewSize);
    if (fromMax) {
      amount = a.getDimension_(element, di, kScrollDim.scrollSize) - amount
        - a.getDimension_(element, di, kScrollDim.viewSize);
    }
    if (isTo) {
      amount -= element ? a.getDimension_(element, di, kScrollDim.position) : di ? scrollY : scrollX;
    }
    if (amount && element === a.top_ && element && window !== top && VDom.parentFrame_()) {
      const Sc = parent && (parent as Window & { VScroller: typeof VScroller; }).VScroller;
{'fraction_non_alphanumeric': 0.12925418569254185, 'fraction_numerical': 0.018508371385083714, 'mean_word_length': 3.0448165476483626, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 27, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '467017', 'n_tokens_mistral': 5606, 'n_tokens_neox': 5256, 'n_words': 1302}