<commit_before>var isFunction = require("is_function"),
    inherits = require("inherits"),
    fastSlice = require("fast_slice"),
    keys = require("keys");

function EventEmitter(maxListeners) {

    this.__events = {};
    this.__maxListeners = maxListeners != null ? maxListeners : EventEmitter.defaultMaxListeners;
}

EventEmitter.prototype.on = function(name, listener) {
    var events, eventList, maxListeners;

    if (!isFunction(listener)) {
        throw new TypeError("EventEmitter.on(name, listener) listener must be a function");
    }

    events = this.__events || (this.__events = {});
    eventList = (events[name] || (events[name] = []));
    maxListeners = this.__maxListeners || -1;

    eventList[eventList.length] = listener;

    if (maxListeners !== -1 && eventList.length > maxListeners) {
        console.error("EventEmitter.on(type, listener) possible EventEmitter memory leak detected. " + maxListeners + " listeners added");
    }

    return this;
};

EventEmitter.prototype.addListener = EventEmitter.prototype.on;

EventEmitter.prototype.once = function(name, listener) {
    var _this = this;

    function once() {
        var length = arguments.length;

        _this.off(name, once);

        if (length === 0) {
            return listener();
        } else if (length === 1) {
            return listener(arguments[0]);
        } else if (length === 2) {
            return listener(arguments[0], arguments[1]);
        } else if (length === 3) {
            return listener(arguments[0], arguments[1], arguments[2]);
        } else if (length === 4) {
            return listener(arguments[0], arguments[1], arguments[2], arguments[3]);
        } else {
            return listener.apply(null, arguments);
        }
    }

    this.on(name, once);

    return once;
};

EventEmitter.prototype.listenTo = function(obj, name) {
    var _this = this;

    if (!(type.isFunction(obj.on) || type.isFunction(obj.addListener))) {
        throw new TypeError("EventEmitter.listenTo(obj, name) obj must have a on function taking (name, listener[, ctx])");
    }

    function handler() {
        _this.emitArgs(name, arguments);
    }

    obj.on(name, handler);

    return handler;
};

EventEmitter.prototype.off = function(name, listener) {
    var events = this.__events || (this.__events = {}),
        eventList, event, i;

    eventList = events[name];
    if (!eventList) {
        return this;
    }

    if (!listener) {
        i = eventList.length;

        while (i--) {
            this.emit("removeListener", name, eventList[i]);
        }
        eventList.length = 0;
        delete events[name];
    } else {
        i = eventList.length;

        while (i--) {
            event = eventList[i];

            if (event === listener) {
                this.emit("removeListener", name, event);
                eventList.splice(i, 1);
            }
        }

        if (eventList.length === 0) {
            delete events[name];
        }
    }

    return this;
};

EventEmitter.prototype.removeListener = EventEmitter.prototype.off;

EventEmitter.prototype.removeAllListeners = function() {
    var events = this.__events || (this.__events = {}),
        objectKeys = keys(events),
        i = -1,
        il = objectKeys.length - 1,
        key, eventList, j;

    while (i++ < il) {
        key = objectKeys[i];
        eventList = events[key];

        if (eventList) {
            j = eventList.length;

            while (j--) {
                this.emit("removeListener", key, eventList[j]);
                eventList.splice(j, 1);
            }
        }

        delete events[key];
    }

    return this;
};

function emit(eventList, args) {
    var a1, a2, a3, a4,
        length = eventList.length - 1,
        i = -1,
        event;

    switch (args.length) {
        case 0:
            while (i++ < length) {
                (event = eventList[i]) && event();
            }
            break;
        case 1:
            a1 = args[0];
            while (i++ < length) {
                (event = eventList[i]) && event(a1);
            }
            break;
        case 2:
            a1 = args[0];
            a2 = args[1];
            while (i++ < length) {
                (event = eventList[i]) && event(a1, a2);
            }
            break;
        case 3:
            a1 = args[0];
            a2 = args[1];
            a3 = args[2];
            while (i++ < length) {
                (event = eventList[i]) && event(a1, a2, a3);
            }
            break;
        case 4:
            a1 = args[0];
            a2 = args[1];
            a3 = args[2];
            a4 = args[3];
            while (i++ < length) {
                (event = eventList[i]) && event(a1, a2, a3, a4);
            }
            break;
        default:
            while (i++ < length) {
                (event = eventList[i]) && event.apply(null, args);
            }
            break;
    }
}

EventEmitter.prototype.emit = function(name) {
    var eventList = (this.__events || (this.__events = {}))[name];

    if (!eventList || !eventList.length) {
        return this;
    }

    emit(eventList, fastSlice(arguments, 1));

    return this;
};

EventEmitter.prototype.emitArgs = function(name, args) {
    var eventList = (this.__events || (this.__events = {}))[name];

    if (!eventList || !eventList.length) {
        return this;
    }

    emit(eventList, args);

    return this;
};

function emitAsync(eventList, args, callback) {
    var length = eventList.length,
        index = 0,
        argsLength = args.length,
        called = false;

    function next(err) {
        if (called === true) {
            return;
        }
        if (index === length || err) {
            called = true;
            callback(err);
            return;
        }

        eventList[index++].apply(null, args);
    }

    args[argsLength] = next;
    next();
}

EventEmitter.prototype.emitAsync = function(name, args, callback) {
    var eventList = (this.__events || (this.__events = {}))[name];

    args = fastSlice(arguments, 1);
    callback = args.pop();

    if (!isFunction(callback)) {
        throw new TypeError("EventEmitter.emitAsync(name [, ...args], callback) callback must be a function");
    }

    if (!eventList || !eventList.length) {
        callback();
    } else {
        emitAsync(eventList, args, callback);
    }

    return this;
};

EventEmitter.prototype.listeners = function(name) {
    var eventList = (this.__events || (this.__events = {}))[name];

    return eventList ? fastSlice(eventList) : [];
};

EventEmitter.prototype.listenerCount = function(name) {
    var eventList = (this.__events || (this.__events = {}))[name];

    return eventList ? eventList.length : 0;
};

EventEmitter.prototype.setMaxListeners = function(value) {
    if ((value = +value) !== value) {
        throw new TypeError("EventEmitter.setMaxListeners(value) value must be a number");
    }

    this.__maxListeners = value < 0 ? -1 : value;
    return this;
};

EventEmitter.defaultMaxListeners = 10;

EventEmitter.listeners = function(obj, name) {
    var eventList;

    if (obj == null) {
        throw new TypeError("EventEmitter.listeners(obj, name) obj required");
    }
    eventList = obj.__events && obj.__events[name];

    return eventList ? fastSlice(eventList) : [];
};

EventEmitter.listenerCount = function(obj, name) {
    var eventList;

    if (obj == null) {
        throw new TypeError("EventEmitter.listenerCount(obj, name) obj required");
    }
    eventList = obj.__events && obj.__events[name];

    return eventList ? eventList.length : 0;
};

EventEmitter.setMaxListeners = function(value) {
    if ((value = +value) !== value) {
        throw new TypeError("EventEmitter.setMaxListeners(value) value must be a number");
    }

    EventEmitter.defaultMaxListeners = value < 0 ? -1 : value;
    return value;
};

EventEmitter.extend = function(child) {

    inherits(child, this);
    child.extend = this.extend;

    return child;
};

module.exports = EventEmitter;
<commit_msg>updates<commit_after>var isFunction = require("is_function"),
    inherits = require("inherits"),
    fastSlice = require("fast_slice"),
    keys = require("keys");

function EventEmitter(maxListeners) {

    this.__events = {};
    this.__maxListeners = maxListeners != null ? maxListeners : EventEmitter.defaultMaxListeners;
}

EventEmitter.prototype.on = function(name, listener) {
    var events, eventList, maxListeners;

    if (!isFunction(listener)) {
        throw new TypeError("EventEmitter.on(name, listener) listener must be a function");
    }

    events = this.__events || (this.__events = {});
    eventList = (events[name] || (events[name] = []));
    maxListeners = this.__maxListeners || -1;

    eventList[eventList.length] = listener;

    if (maxListeners !== -1 && eventList.length > maxListeners) {
        console.error("EventEmitter.on(type, listener) possible EventEmitter memory leak detected. " + maxListeners + " listeners added");
    }

    return this;
};

EventEmitter.prototype.addListener = EventEmitter.prototype.on;

EventEmitter.prototype.once = function(name, listener) {
    var _this = this;

    function once() {
        var length = arguments.length;

        _this.off(name, once);

        if (length === 0) {
            return listener();
        } else if (length === 1) {
            return listener(arguments[0]);
        } else if (length === 2) {
            return listener(arguments[0], arguments[1]);
        } else if (length === 3) {
            return listener(arguments[0], arguments[1], arguments[2]);
        } else if (length === 4) {
            return listener(arguments[0], arguments[1], arguments[2], arguments[3]);
        } else {
            return listener.apply(null, arguments);
        }
    }

    this.on(name, once);

    return once;
};

EventEmitter.prototype.listenTo = function(obj, name) {
    var _this = this;

    if (!(type.isFunction(obj.on) || type.isFunction(obj.addListener))) {
        throw new TypeError("EventEmitter.listenTo(obj, name) obj must have a on function taking (name, listener[, ctx])");
    }

    function handler() {
        _this.emitArgs(name, arguments);
    }

    obj.on(name, handler);

    return handler;
};

EventEmitter.prototype.off = function(name, listener) {
    var events = this.__events || (this.__events = {}),
        eventList, event, i;

    eventList = events[name];
    if (!eventList) {
        return this;
    }

    if (!listener) {
        i = eventList.length;

        while (i--) {
            this.emit("removeListener", name, eventList[i]);
        }
        eventList.length = 0;
        delete events[name];
    } else {
        i = eventList.length;

        while (i--) {
            event = eventList[i];

            if (event === listener) {
                this.emit("removeListener", name, event);
                eventList.splice(i, 1);
            }
        }

        if (eventList.length === 0) {
            delete events[name];
        }
    }

    return this;
};

EventEmitter.prototype.removeListener = EventEmitter.prototype.off;

EventEmitter.prototype.removeAllListeners = function() {
    var events = this.__events || (this.__events = {}),
        objectKeys = keys(events),
        i = -1,
        il = objectKeys.length - 1,
        key, eventList, j;

    while (i++ < il) {
        key = objectKeys[i];
        eventList = events[key];

        if (eventList) {
            j = eventList.length;

            while (j--) {
                this.emit("removeListener", key, eventList[j]);
                eventList.splice(j, 1);
            }
        }

        delete events[key];
    }

    return this;
};

function emit(eventList, args) {
    var a1, a2, a3, a4,
        length = eventList.length - 1,
        i = -1,
        event;

    switch (args.length) {
        case 0:
            while (i++ < length) {
                (event = eventList[i]) && event();
            }
            break;
        case 1:
            a1 = args[0];
            while (i++ < length) {
                (event = eventList[i]) && event(a1);
            }
            break;
        case 2:
            a1 = args[0];
            a2 = args[1];
            while (i++ < length) {
                (event = eventList[i]) && event(a1, a2);
            }
            break;
        case 3:
            a1 = args[0];
            a2 = args[1];
            a3 = args[2];
            while (i++ < length) {
                (event = eventList[i]) && event(a1, a2, a3);
            }
            break;
        case 4:
            a1 = args[0];
            a2 = args[1];
            a3 = args[2];
            a4 = args[3];
            while (i++ < length) {
                (event = eventList[i]) && event(a1, a2, a3, a4);
            }
            break;
        default:
            while (i++ < length) {
                (event = eventList[i]) && event.apply(null, args);
            }
            break;
    }
}

EventEmitter.prototype.emit = function(name) {
    var eventList = (this.__events || (this.__events = {}))[name];

    if (!eventList || !eventList.length) {
        return this;
    }

    emit(eventList, fastSlice(arguments, 1));

    return this;
};

EventEmitter.prototype.emitArgs = function(name, args) {
    var eventList = (this.__events || (this.__events = {}))[name];

    if (!eventList || !eventList.length) {
        return this;
    }

    emit(eventList, args);

    return this;
};

function emitAsync(eventList, args, callback) {
    var length = eventList.length,
        index = 0,
        called = false;

    function next(err) {
        if (called === true) {
            return;
        }
        if (err || index === length) {
            called = true;
            callback(err);
            return;
        }

        eventList[index++].apply(null, args);
    }

    args[args.length] = next;
    next();
}

EventEmitter.prototype.emitAsync = function(name, args, callback) {
    var eventList = (this.__events || (this.__events = {}))[name];

    args = fastSlice(arguments, 1);
    callback = args.pop();

    if (!isFunction(callback)) {
        throw new TypeError("EventEmitter.emitAsync(name [, ...args], callback) callback must be a function");
    }

    if (!eventList || !eventList.length) {
        callback();
    } else {
        emitAsync(eventList, args, callback);
    }

    return this;
};

EventEmitter.prototype.listeners = function(name) {
    var eventList = (this.__events || (this.__events = {}))[name];

    return eventList ? fastSlice(eventList) : [];
};

EventEmitter.prototype.listenerCount = function(name) {
    var eventList = (this.__events || (this.__events = {}))[name];

    return eventList ? eventList.length : 0;
};

EventEmitter.prototype.setMaxListeners = function(value) {
    if ((value = +value) !== value) {
        throw new TypeError("EventEmitter.setMaxListeners(value) value must be a number");
    }

    this.__maxListeners = value < 0 ? -1 : value;
    return this;
};

EventEmitter.defaultMaxListeners = 10;

EventEmitter.listeners = function(obj, name) {
    var eventList;

    if (obj == null) {
        throw new TypeError("EventEmitter.listeners(obj, name) obj required");
    }
    eventList = obj.__events && obj.__events[name];

    return eventList ? fastSlice(eventList) : [];
};

EventEmitter.listenerCount = function(obj, name) {
    var eventList;

    if (obj == null) {
        throw new TypeError("EventEmitter.listenerCount(obj, name) obj required");
    }
    eventList = obj.__events && obj.__events[name];

    return eventList ? eventList.length : 0;
};

EventEmitter.setMaxListeners = function(value) {
    if ((value = +value) !== value) {
        throw new TypeError("EventEmitter.setMaxListeners(value) value must be a number");
    }

    EventEmitter.defaultMaxListeners = value < 0 ? -1 : value;
    return value;
};

EventEmitter.extend = function(child) {

    inherits(child, this);
    child.extend = this.extend;

    return child;
};

module.exports = EventEmitter;
<|endoftext|>


<commit_before>const SCROLL_TIMEOUT_DEFAULT = 300
const SCROLL_TIME_DEFAULT = 2
const NOOP = () => {}

export default function (element, config) {
  if (
    config.scrollTimeout &&
    (isNaN(config.scrollTimeout) || typeof config.scrollTimeout === 'boolean')
  ) {
    throw new Error(
      `Optional config property 'scrollTimeout' is not valid, expected NUMBER but found ${(typeof config.scrollTimeout).toUpperCase()}`
    )
  }
  const SCROLL_TIMEOUT = config.scrollTimeout || SCROLL_TIMEOUT_DEFAULT

  if (config.scrollTime && (isNaN(config.scrollTime) || typeof config.scrollTime === 'boolean')) {
    throw new Error(
      `Optional config property 'scrollTime' is not valid, expected NUMBER but found ${(typeof config.scrollTime).toUpperCase()}`
    )
  }
  const SCROLL_TIME = config.scrollTime || SCROLL_TIME_DEFAULT

  if (!config.scrollSnapDestination) {
    throw new Error('Required config property scrollSnapDestination is not defined')
  }
  const SCROLL_SNAP_DESTINATION = config.scrollSnapDestination

  let onAnimationEnd
  let timeOutId = null
  let scrollStart = null
  let animating = false
  let timer = 0
  let speedDeltaX
  let speedDeltaY
  let target
  let lastObj
  let lastScrollObj
  let lastScrollValue = {
    x: null,
    y: null
  }

  function checkScrollSpeed (value, axis) {
    function clear () {
      lastScrollValue[axis] = null
    }

    const newValue = value
    let delta
    if (lastScrollValue[axis] !== null) {
      delta = newValue - lastScrollValue[axis]
    } else {
      delta = 0
    }
    lastScrollValue[axis] = newValue
    timer && clearTimeout(timer)
    timer = setTimeout(clear, 50)
    return delta
  }

  function saveDeclaration (obj) {
    obj.snapLengthUnit = parseSnapCoordValue(SCROLL_SNAP_DESTINATION)
  }

  function bindElement (element) {
    target = element === document ? document.body : element

    /**
     * set webkit-overflow-scrolling to auto.
     * this prevents momentum scrolling on ios devices
     * causing flickering behaviours and delayed transitions.
     */
    element.style.overflow = 'auto'
    element.style.webkitOverflowScrolling = 'auto'

    element.addEventListener('scroll', startAnimation, false)
    saveDeclaration(target)
  }

  function unbindElement (element) {
    element.style.webkitOverflowScrolling = null
    element.removeEventListener('scroll', startAnimation, false)
  }

  function startAnimation () {
    speedDeltaX = checkScrollSpeed(target.scrollLeft, 'x')
    speedDeltaY = checkScrollSpeed(target.scrollTop, 'y')
    if (animating || (speedDeltaX === 0 && speedDeltaY === 0)) {
      return
    }

    handler(target)
  }

  /**
   * scroll handler
   * this is the callback for scroll events.
   */
  function handler (target) {
    // use evt.target as target-element
    lastObj = target

    lastScrollObj = getScrollObj(lastObj)

    // if currently animating, stop it. this prevents flickering.
    if (animationFrame) {
      // cross browser
      if (!window.cancelAnimationFrame(animationFrame)) {
        clearTimeout(animationFrame)
      }
    }

    // if a previous timeout exists, clear it.
    if (timeOutId) {
      // we only want to call a timeout once after scrolling..
      clearTimeout(timeOutId)
    } else {
      scrollStart = {
        y: lastScrollObj.scrollTop,
        x: lastScrollObj.scrollLeft
      }
    }

    timeOutId = setTimeout(animationHandler, SCROLL_TIMEOUT)
  }

  function animationHandler () {
    // if we don't move a thing, we can ignore the timeout: if we did, there'd be another timeout added for scrollStart+1.
    if (scrollStart.y === lastScrollObj.scrollTop && scrollStart.x === lastScrollObj.scrollLeft) {
      // ignore timeout
      return
    }

    // detect direction of scroll. negative is up, positive is down.
    let direction = {
      y: speedDeltaY > 0 ? 1 : -1,
      x: speedDeltaX > 0 ? 1 : -1
    }
    let snapPoint

    // get the next snap-point to snap-to
    snapPoint = getNextSnapPoint(lastScrollObj, lastObj, direction)

    lastObj.removeEventListener('scroll', startAnimation, false)

    animating = true

    // smoothly move to the snap point
    smoothScroll(lastScrollObj, snapPoint, function () {
      // after moving to the snap point, rebind the scroll event handler
      animating = false
      lastObj.addEventListener('scroll', startAnimation, false)
      onAnimationEnd()
    })

    // we just jumped to the snapPoint, so this will be our next scrollStart
    if (!isNaN(snapPoint.x || !isNaN(snapPoint.y))) {
      scrollStart = snapPoint
    }
  }

  /**
   * calculator for next snap-point
   * @param  {Object} scrollObj - DOM element
   * @param  {Object} obj - DOM element
   * @param  {integer} direction - signed integer indicating the scroll direction
   * @return {Object}
   */
  function getNextSnapPoint (scrollObj, obj, direction) {
    // get snap length
    let snapLength = {
      y: roundByDirection(direction.y, getYSnapLength(obj, obj.snapLengthUnit.y)),
      x: roundByDirection(direction.x, getXSnapLength(obj, obj.snapLengthUnit.x))
    }
    let top = scrollObj.scrollTop
    let left = scrollObj.scrollLeft

    // calc current and initial snappoint
    let currentPoint = {
      y: top / snapLength.y || 1,
      x: left / snapLength.x || 1
    }
    let nextPoint = {
      y: 0,
      x: 0
    }

    // set target and bounds by direction
    nextPoint.y = roundByDirection(direction.y, currentPoint.y)
    nextPoint.x = roundByDirection(direction.x, currentPoint.x)

    // calculate where to scroll
    const scrollTo = {
      y: nextPoint.y * snapLength.y,
      x: nextPoint.x * snapLength.x
    }

    // stay in bounds (minimum: 0, maxmimum: absolute height)
    scrollTo.y = stayInBounds(0, scrollObj.scrollHeight, scrollTo.y)
    scrollTo.x = stayInBounds(0, scrollObj.scrollWidth, scrollTo.x)

    return scrollTo
  }

  /**
   * ceil or floor a number based on direction
   * @param  {Number} direction
   * @param  {Number} currentPoint
   * @return {Number}
   */
  function roundByDirection (direction, currentPoint) {
    if (direction === -1) {
      // when we go up, we floor the number to jump to the next snap-point in scroll direction
      return Math.floor(currentPoint)
    }
    // go down, we ceil the number to jump to the next in view.
    return Math.ceil(currentPoint)
  }

  /**
   * keep scrolling in bounds
   * @param  {Number} min
   * @param  {Number} max
   * @param  {Number} destined
   * @return {Number}
   */
  function stayInBounds (min, max, destined) {
    return Math.max(Math.min(destined, max), min)
  }

  /**
   * parse snap destination/coordinate values.
   * @param  {Object} declaration
   * @return {Object}
   */
  function parseSnapCoordValue (declaration) {
    // regex to parse lengths
    let regex = /(\d+)(px|%|vw) (\d+)(px|%|vh)/g
    // defaults
    let parsed = {
      y: {
        value: 0,
        unit: 'px'
      },
      x: {
        value: 0,
        unit: 'px'
      }
    }
    let parsable
    let result

    // parse value and unit
    if (parsable !== null) {
      result = regex.exec(declaration)
      // if regexp fails, value is null
      if (result !== null) {
        parsed.x = {
          value: result[1],
          unit: result[2]
        }
        parsed.y = {
          value: result[3],
          unit: result[4]
        }
      }
    }
    return parsed
  }

  /**
   * calc length of one snap on y-axis
   * @param  {Object} obj the scroll object
   * @param  {Object} declaration the parsed declaration
   * @return {Number}
   */
  function getYSnapLength (obj, declaration) {
    if (declaration.unit === 'vh') {
      // when using vh, one snap is the length of vh / 100 * value
      return (
        Math.max(document.documentElement.clientHeight, window.innerHeight || 1) /
        100 *
        declaration.value
      )
    } else if (declaration.unit === '%') {
      // when using %, one snap is the length of element height / 100 * value
      return obj.offsetHeight / 100 * declaration.value
    } else {
      // when using px, one snap is the length of element height / value
      return obj.offsetHeight / declaration.value
    }
  }

  /**
   * calc length of one snap on x-axis
   * @param  {Object} obj the scroll object
   * @param  {Object} declaration the parsed declaration
   * @return {Number}
   */
  function getXSnapLength (obj, declaration) {
    if (declaration.unit === 'vw') {
      // when using vw, one snap is the length of vw / 100 * value
      return (
        Math.max(document.documentElement.clientWidth, window.innerWidth || 1) /
        100 *
        declaration.value
      )
    } else if (declaration.unit === '%') {
      // when using %, one snap is the length of element width / 100 * value
      return obj.offsetWidth / 100 * declaration.value
    } else {
      // when using px, one snap is the length of element width / value
      return obj.offsetWidth / declaration.value
    }
  }

  /**
   * return the element scrolling values are applied to.
   * when receiving window.onscroll events, the actual scrolling is on the body.
   * @param  {Object} obj - DOM element
   * @return {Object}
   */
  function getScrollObj (obj) {
    // if the scroll container is body, the scrolling is invoked on window/document.
    if (obj === document || obj === window) {
      // firefox scrolls on document.documentElement
      if (document.documentElement.scrollTop > 0 || document.documentElement.scrollLeft > 0) {
        return document.documentElement
      }
      // chrome scrolls on body
      return document.querySelector('body')
    }

    return obj
  }

  /**
   * ease in cubic function
   * @param  {Number} t current time of the tween
   * @param  {Number} b beginning value of the property
   * @param  {Number} c change between the beginning and destination value
   * @param  {Number} d is the total time of the tween
   * @return {Number}   easing factor
   */
  function easeInCubic (t, b, c, d) {
    return c * (t = t / d) * t * t + b
  }

  /**
   * calculate the scroll position we should be in
   * @param  {Number} start    the start point of the scroll
   * @param  {Number} end      the end point of the scroll
   * @param  {Number} elapsed  the time elapsed from the beginning of the scroll
   * @param  {Number} duration the total duration of the scroll (default 500ms)
   * @return {Number}          the next position
   */
  function position (start, end, elapsed, duration) {
    if (elapsed > duration) {
      return end
    }
    return easeInCubic(elapsed, start, end - start, duration)
  }

  /**
   * is the starting position at the edge of the container?
   * @param  {Object} start    the start coordinates of the scroll
   * @param  {Object} end      the end coordinates of the scroll
   * @return {Boolean}
   */
  function isEdge (start, end) {
    return (start.x === 0 && speedDeltaY === 0) || (start.y === 0 && speedDeltaX === 0)
  }

  // a current animation frame
  let animationFrame = null

  /**
   * smoothScroll function by Alice Lietieur.
   * @see https://github.com/alicelieutier/smoothScroll
   * we use requestAnimationFrame to be called by the browser before every repaint
   * @param  {Object}   obj      the scroll context
   * @param  {Number}  end      where to scroll to
   * @param  {Function} callback called when the scrolling is finished
   */
  function smoothScroll (obj, end, callback) {
    let start = {
      y: obj.scrollTop,
      x: obj.scrollLeft
    }

    // get animation frame or a fallback
    let requestAnimationFrame =
      window.requestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      function (fn) {
        window.setTimeout(fn, 15)
      }
    let duration = isEdge(start, end) ? 0 : SCROLL_TIME
    let startTime = null

    // setup the stepping function
    function step (timestamp) {
      if (!startTime) {
        startTime = timestamp
      }
      const elapsed = timestamp - startTime

      // change position on y-axis if result is a number.
      if (!isNaN(end.y)) {
        obj.scrollTop = position(start.y, end.y, elapsed, duration)
      }

      // change position on x-axis if result is a number.
      if (!isNaN(end.x)) {
        obj.scrollLeft = position(start.x, end.x, elapsed, duration)
      }

      // check if we are over due;
      if (elapsed < duration) {
        requestAnimationFrame(step)
      } else {
        // is there a callback?
        if (typeof callback === 'function') {
          // stop execution and run the callback
          return callback(end)
        }
      }
    }
    animationFrame = requestAnimationFrame(step)
  }

  this.bind = function (callback) {
    onAnimationEnd = typeof callback === 'function' ? callback : NOOP

    bindElement(element)
  }

  this.unbind = function () {
    unbindElement(element)
  }

  return this
}
<commit_msg>Fix potentially incorrect condition<commit_after>const SCROLL_TIMEOUT_DEFAULT = 300
const SCROLL_TIME_DEFAULT = 2
const NOOP = () => {}

export default function (element, config) {
  if (
    config.scrollTimeout &&
    (isNaN(config.scrollTimeout) || typeof config.scrollTimeout === 'boolean')
  ) {
    throw new Error(
      `Optional config property 'scrollTimeout' is not valid, expected NUMBER but found ${(typeof config.scrollTimeout).toUpperCase()}`
    )
  }
  const SCROLL_TIMEOUT = config.scrollTimeout || SCROLL_TIMEOUT_DEFAULT

  if (config.scrollTime && (isNaN(config.scrollTime) || typeof config.scrollTime === 'boolean')) {
    throw new Error(
      `Optional config property 'scrollTime' is not valid, expected NUMBER but found ${(typeof config.scrollTime).toUpperCase()}`
    )
  }
  const SCROLL_TIME = config.scrollTime || SCROLL_TIME_DEFAULT

  if (!config.scrollSnapDestination) {
    throw new Error('Required config property scrollSnapDestination is not defined')
  }
  const SCROLL_SNAP_DESTINATION = config.scrollSnapDestination

  let onAnimationEnd
  let timeOutId = null
  let scrollStart = null
  let animating = false
  let timer = 0
  let speedDeltaX
  let speedDeltaY
  let target
  let lastObj
  let lastScrollObj
  let lastScrollValue = {
    x: null,
    y: null
  }

  function checkScrollSpeed (value, axis) {
    function clear () {
      lastScrollValue[axis] = null
    }

    const newValue = value
    let delta
    if (lastScrollValue[axis] !== null) {
      delta = newValue - lastScrollValue[axis]
    } else {
      delta = 0
    }
    lastScrollValue[axis] = newValue
    timer && clearTimeout(timer)
    timer = setTimeout(clear, 50)
    return delta
  }

  function saveDeclaration (obj) {
    obj.snapLengthUnit = parseSnapCoordValue(SCROLL_SNAP_DESTINATION)
  }

  function bindElement (element) {
    target = element === document ? document.body : element

    /**
     * set webkit-overflow-scrolling to auto.
     * this prevents momentum scrolling on ios devices
     * causing flickering behaviours and delayed transitions.
     */
    element.style.overflow = 'auto'
    element.style.webkitOverflowScrolling = 'auto'

    element.addEventListener('scroll', startAnimation, false)
    saveDeclaration(target)
  }

  function unbindElement (element) {
    element.style.webkitOverflowScrolling = null
    element.removeEventListener('scroll', startAnimation, false)
  }

  function startAnimation () {
    speedDeltaX = checkScrollSpeed(target.scrollLeft, 'x')
    speedDeltaY = checkScrollSpeed(target.scrollTop, 'y')
    if (animating || (speedDeltaX === 0 && speedDeltaY === 0)) {
      return
    }

    handler(target)
  }

  /**
   * scroll handler
   * this is the callback for scroll events.
   */
  function handler (target) {
    // use evt.target as target-element
    lastObj = target

    lastScrollObj = getScrollObj(lastObj)

    // if currently animating, stop it. this prevents flickering.
    if (animationFrame) {
      // cross browser
      if (!window.cancelAnimationFrame(animationFrame)) {
        clearTimeout(animationFrame)
      }
    }

    // if a previous timeout exists, clear it.
    if (timeOutId) {
      // we only want to call a timeout once after scrolling..
      clearTimeout(timeOutId)
    } else {
      scrollStart = {
        y: lastScrollObj.scrollTop,
        x: lastScrollObj.scrollLeft
      }
    }

    timeOutId = setTimeout(animationHandler, SCROLL_TIMEOUT)
  }

  function animationHandler () {
    // if we don't move a thing, we can ignore the timeout: if we did, there'd be another timeout added for scrollStart+1.
    if (scrollStart.y === lastScrollObj.scrollTop && scrollStart.x === lastScrollObj.scrollLeft) {
      // ignore timeout
      return
    }

    // detect direction of scroll. negative is up, positive is down.
    let direction = {
      y: speedDeltaY > 0 ? 1 : -1,
      x: speedDeltaX > 0 ? 1 : -1
    }
    let snapPoint

    // get the next snap-point to snap-to
    snapPoint = getNextSnapPoint(lastScrollObj, lastObj, direction)

    lastObj.removeEventListener('scroll', startAnimation, false)

    animating = true

    // smoothly move to the snap point
    smoothScroll(lastScrollObj, snapPoint, function () {
      // after moving to the snap point, rebind the scroll event handler
      animating = false
      lastObj.addEventListener('scroll', startAnimation, false)
      onAnimationEnd()
    })

    // we just jumped to the snapPoint, so this will be our next scrollStart
    if (!isNaN(snapPoint.x) || !isNaN(snapPoint.y)) {
      scrollStart = snapPoint
    }
  }

  /**
   * calculator for next snap-point
   * @param  {Object} scrollObj - DOM element
   * @param  {Object} obj - DOM element
   * @param  {integer} direction - signed integer indicating the scroll direction
   * @return {Object}
   */
  function getNextSnapPoint (scrollObj, obj, direction) {
    // get snap length
    let snapLength = {
      y: roundByDirection(direction.y, getYSnapLength(obj, obj.snapLengthUnit.y)),
      x: roundByDirection(direction.x, getXSnapLength(obj, obj.snapLengthUnit.x))
    }
    let top = scrollObj.scrollTop
    let left = scrollObj.scrollLeft

    // calc current and initial snappoint
    let currentPoint = {
      y: top / snapLength.y || 1,
      x: left / snapLength.x || 1
    }
    let nextPoint = {
      y: 0,
      x: 0
    }

    // set target and bounds by direction
    nextPoint.y = roundByDirection(direction.y, currentPoint.y)
    nextPoint.x = roundByDirection(direction.x, currentPoint.x)

    // calculate where to scroll
    const scrollTo = {
      y: nextPoint.y * snapLength.y,
      x: nextPoint.x * snapLength.x
    }

    // stay in bounds (minimum: 0, maxmimum: absolute height)
    scrollTo.y = stayInBounds(0, scrollObj.scrollHeight, scrollTo.y)
    scrollTo.x = stayInBounds(0, scrollObj.scrollWidth, scrollTo.x)

    return scrollTo
  }

  /**
   * ceil or floor a number based on direction
   * @param  {Number} direction
   * @param  {Number} currentPoint
   * @return {Number}
   */
  function roundByDirection (direction, currentPoint) {
    if (direction === -1) {
      // when we go up, we floor the number to jump to the next snap-point in scroll direction
      return Math.floor(currentPoint)
    }
    // go down, we ceil the number to jump to the next in view.
    return Math.ceil(currentPoint)
  }

  /**
   * keep scrolling in bounds
   * @param  {Number} min
   * @param  {Number} max
   * @param  {Number} destined
   * @return {Number}
   */
  function stayInBounds (min, max, destined) {
    return Math.max(Math.min(destined, max), min)
  }

  /**
   * parse snap destination/coordinate values.
   * @param  {Object} declaration
   * @return {Object}
   */
  function parseSnapCoordValue (declaration) {
    // regex to parse lengths
    let regex = /(\d+)(px|%|vw) (\d+)(px|%|vh)/g
    // defaults
    let parsed = {
      y: {
        value: 0,
        unit: 'px'
      },
      x: {
        value: 0,
        unit: 'px'
      }
    }
    let parsable
    let result

    // parse value and unit
    if (parsable !== null) {
      result = regex.exec(declaration)
      // if regexp fails, value is null
      if (result !== null) {
        parsed.x = {
          value: result[1],
          unit: result[2]
        }
        parsed.y = {
          value: result[3],
          unit: result[4]
        }
      }
    }
    return parsed
  }

  /**
   * calc length of one snap on y-axis
   * @param  {Object} obj the scroll object
   * @param  {Object} declaration the parsed declaration
   * @return {Number}
   */
  function getYSnapLength (obj, declaration) {
    if (declaration.unit === 'vh') {
      // when using vh, one snap is the length of vh / 100 * value
      return (
        Math.max(document.documentElement.clientHeight, window.innerHeight || 1) /
        100 *
        declaration.value
      )
    } else if (declaration.unit === '%') {
      // when using %, one snap is the length of element height / 100 * value
      return obj.offsetHeight / 100 * declaration.value
    } else {
      // when using px, one snap is the length of element height / value
      return obj.offsetHeight / declaration.value
    }
  }

  /**
   * calc length of one snap on x-axis
   * @param  {Object} obj the scroll object
   * @param  {Object} declaration the parsed declaration
   * @return {Number}
   */
  function getXSnapLength (obj, declaration) {
    if (declaration.unit === 'vw') {
      // when using vw, one snap is the length of vw / 100 * value
      return (
        Math.max(document.documentElement.clientWidth, window.innerWidth || 1) /
        100 *
        declaration.value
      )
    } else if (declaration.unit === '%') {
      // when using %, one snap is the length of element width / 100 * value
      return obj.offsetWidth / 100 * declaration.value
    } else {
      // when using px, one snap is the length of element width / value
      return obj.offsetWidth / declaration.value
    }
  }

  /**
   * return the element scrolling values are applied to.
   * when receiving window.onscroll events, the actual scrolling is on the body.
   * @param  {Object} obj - DOM element
   * @return {Object}
   */
  function getScrollObj (obj) {
    // if the scroll container is body, the scrolling is invoked on window/document.
    if (obj === document || obj === window) {
      // firefox scrolls on document.documentElement
      if (document.documentElement.scrollTop > 0 || document.documentElement.scrollLeft > 0) {
        return document.documentElement
      }
      // chrome scrolls on body
      return document.querySelector('body')
    }

    return obj
  }

  /**
   * ease in cubic function
   * @param  {Number} t current time of the tween
   * @param  {Number} b beginning value of the property
   * @param  {Number} c change between the beginning and destination value
   * @param  {Number} d is the total time of the tween
   * @return {Number}   easing factor
   */
  function easeInCubic (t, b, c, d) {
    return c * (t = t / d) * t * t + b
  }

  /**
   * calculate the scroll position we should be in
   * @param  {Number} start    the start point of the scroll
   * @param  {Number} end      the end point of the scroll
   * @param  {Number} elapsed  the time elapsed from the beginning of the scroll
   * @param  {Number} duration the total duration of the scroll (default 500ms)
   * @return {Number}          the next position
   */
  function position (start, end, elapsed, duration) {
    if (elapsed > duration) {
      return end
    }
    return easeInCubic(elapsed, start, end - start, duration)
  }

  /**
   * is the starting position at the edge of the container?
   * @param  {Object} start    the start coordinates of the scroll
   * @param  {Object} end      the end coordinates of the scroll
   * @return {Boolean}
   */
  function isEdge (start, end) {
    return (start.x === 0 && speedDeltaY === 0) || (start.y === 0 && speedDeltaX === 0)
  }

  // a current animation frame
  let animationFrame = null

  /**
   * smoothScroll function by Alice Lietieur.
   * @see https://github.com/alicelieutier/smoothScroll
   * we use requestAnimationFrame to be called by the browser before every repaint
   * @param  {Object}   obj      the scroll context
   * @param  {Number}  end      where to scroll to
   * @param  {Function} callback called when the scrolling is finished
   */
  function smoothScroll (obj, end, callback) {
    let start = {
      y: obj.scrollTop,
      x: obj.scrollLeft
    }

    // get animation frame or a fallback
    let requestAnimationFrame =
      window.requestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      function (fn) {
        window.setTimeout(fn, 15)
      }
    let duration = isEdge(start, end) ? 0 : SCROLL_TIME
    let startTime = null

    // setup the stepping function
    function step (timestamp) {
      if (!startTime) {
        startTime = timestamp
      }
      const elapsed = timestamp - startTime

      // change position on y-axis if result is a number.
      if (!isNaN(end.y)) {
        obj.scrollTop = position(start.y, end.y, elapsed, duration)
      }

      // change position on x-axis if result is a number.
      if (!isNaN(end.x)) {
        obj.scrollLeft = position(start.x, end.x, elapsed, duration)
      }

      // check if we are over due;
      if (elapsed < duration) {
        requestAnimationFrame(step)
      } else {
        // is there a callback?
        if (typeof callback === 'function') {
          // stop execution and run the callback
          return callback(end)
        }
      }
    }
    animationFrame = requestAnimationFrame(step)
  }

  this.bind = function (callback) {
    onAnimationEnd = typeof callback === 'function' ? callback : NOOP

    bindElement(element)
  }

  this.unbind = function () {
    unbindElement(element)
  }

  return this
}
<|endoftext|>


<commit_before>// @flow
import type {
  JQueryWrapper,
  State,
  Options,
  UpdateCallback,
  EventListeners,
  Rect,
  Modifier,
} from './types';

// DOM Utils
import getElementClientRect from './dom-utils/getElementClientRect';
import listScrollParents from './dom-utils/listScrollParents';
import getWindow from './dom-utils/getWindow';
import getNodeScroll from './dom-utils/getNodeScroll';
import getOffsetParent from './dom-utils/getOffsetParent';

// Pure Utils
import unwrapJqueryElement from './utils/unwrapJqueryElement';
import orderModifiers from './utils/orderModifiers';
import expandToHashMap from './utils/expandToHashMap';
import format from './utils/format';
import debounce from './utils/debounce';
import validateModifiers from './utils/validateModifiers';

const INVALID_ELEMENT_ERROR =
  'Popper: Invalid reference or popper argument provided to Popper, they must be either a valid DOM element or a jQuery-wrapped DOM element.';
const INFINITE_LOOP_ERROR =
  'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.';

const areValidElements = (a: mixed, b: mixed): boolean %checks =>
  a instanceof Element && b instanceof Element;

const defaultOptions = {
  placement: 'bottom',
  eventListeners: { scroll: true, resize: true },
  modifiers: [],
  strategy: 'absolute',
};

export default class Popper {
  static defaultModifiers: Array<Modifier<any>>;
  state: $Shape<State> = {
    placement: 'bottom',
    orderedModifiers: [],
    options: defaultOptions,
    modifiersData: {},
  };

  constructor(
    reference: Element | JQueryWrapper,
    popper: Element | JQueryWrapper,
    options: $Shape<Options> = defaultOptions
  ) {
    // Unwrap `reference` and `popper` elements in case they are
    // wrapped by jQuery, otherwise consume them as is
    this.state.elements = {
      reference: unwrapJqueryElement(reference),
      popper: unwrapJqueryElement(popper),
    };
    const {
      reference: referenceElement,
      popper: popperElement,
    } = this.state.elements;

    // Store options into state
    this.state.options = { ...defaultOptions, ...options };

    // Don't proceed if `reference` or `popper` are invalid elements
    if (!areValidElements(referenceElement, popperElement)) {
      if (__DEV__) {
        console.error(INVALID_ELEMENT_ERROR);
      }
      return;
    }

    this.state.scrollParents = {
      reference: listScrollParents(referenceElement),
      popper: listScrollParents(popperElement),
    };

    // Order `options.modifiers` so that the dependencies are fulfilled
    // once the modifiers are executed
    this.state.orderedModifiers = orderModifiers([
      ...this.constructor.defaultModifiers,
      ...this.state.options.modifiers,
    ])
      // Apply user defined preferences to modifiers
      .map(modifier => ({
        ...modifier,
        ...this.state.options.modifiers.find(
          ({ name }) => name === modifier.name
        ),
      }));

    // Validate the provided modifiers so that the consumer will get warned
    // of one of the custom modifiers is invalid for any reason
    if (__DEV__) {
      validateModifiers(this.state.options.modifiers);
    }

    // Modifiers have the opportunity to execute some arbitrary code before
    // the first update cycle is ran, the order of execution will be the same
    // defined by the modifier dependencies directive.
    // The `onLoad` function may add or alter the options of themselves
    this.state.orderedModifiers.forEach(
      ({ onLoad, enabled }) => enabled && onLoad && onLoad(this.state)
    );

    this.update().then(() => {
      // After the first update completed, enable the event listeners
      this.enableEventListeners(this.state.options.eventListeners);
    });
  }

  // Async and optimistically optimized update
  // it will not be executed if not necessary
  // debounced, so that it only runs at most once-per-tick
  update = debounce(
    () =>
      new Promise<State>((success, reject) => {
        this.forceUpdate();
        success(this.state);
      })
  );

  // Syncronous and forcefully executed update
  // it will always be executed even if not necessary, usually NOT needed
  // use Popper#update instead
  forceUpdate() {
    const {
      reference: referenceElement,
      popper: popperElement,
    } = this.state.elements;
    // Don't proceed if `reference` or `popper` are not valid elements anymore
    if (!areValidElements(referenceElement, popperElement)) {
      if (__DEV__) {
        console.error(INVALID_ELEMENT_ERROR);
      }
      return;
    }

    // Get initial measurements
    // these are going to be used to compute the initial popper offsets
    // and as cache for any modifier that needs them later
    this.state.measures = {
      reference: getElementClientRect(referenceElement),
      popper: getElementClientRect(popperElement),
    };

    // Get scrollTop and scrollLeft of the offsetParent
    // this will be used in the `computeOffsets` function to properly
    // position the popper taking in account the scroll position
    // FIXME: right now we only look for a single offsetParent (the popper one)
    //        but we really want to take in account the reference offsetParent as well
    const offsetParentScroll = getNodeScroll(getOffsetParent(popperElement));

    // Modifiers have the ability to read the current Popper state, included
    // the popper offsets, and modify it to address specifc cases
    this.state.reset = false;

    // Cache the placement in cache to make it available to the modifiers
    // modifiers will modify this one (rather than the one in options)
    this.state.placement = this.state.options.placement;

    this.state.orderedModifiers.forEach(
      modifier =>
        (this.state.modifiersData[modifier.name] = {
          ...modifier.data,
        })
    );

    let __debug_loops__ = 0;
    for (let index = 0; index < this.state.orderedModifiers.length; index++) {
      if (__DEV__) {
        __debug_loops__ += 1;
        if (__debug_loops__ > 100) {
          console.error(INFINITE_LOOP_ERROR);
          break;
        }
      }

      if (this.state.reset === true) {
        this.state.reset = false;
        index = -1;
        continue;
      }

      const { fn, enabled, options } = this.state.orderedModifiers[index];

      if (enabled && typeof fn === 'function') {
        this.state = fn((this.state: State), options);
      }
    }
  }

  enableEventListeners(
    eventListeners: boolean | {| scroll?: boolean, resize?: boolean |}
  ) {
    const {
      reference: referenceElement,
      popper: popperElement,
    } = this.state.elements;
    const { scroll, resize } =
      typeof eventListeners === 'boolean'
        ? expandToHashMap(eventListeners, ['scroll', 'resize'])
        : eventListeners;

    if (scroll) {
      const scrollParents = [
        ...this.state.scrollParents.reference,
        ...this.state.scrollParents.popper,
      ];

      scrollParents.forEach(scrollParent =>
        scrollParent.addEventListener('scroll', this.update, {
          passive: true,
        })
      );
    }

    if (resize) {
      const window = getWindow(this.state.elements.popper);
      window.addEventListener('resize', this.update, {
        passive: true,
      });
    }
  }

  destroy() {
    // Remove scroll event listeners
    const scrollParents = [
      ...this.state.scrollParents.reference,
      ...this.state.scrollParents.popper,
    ];

    scrollParents.forEach(scrollParent =>
      scrollParent.removeEventListener('scroll', this.update)
    );

    // Remove resize event listeners
    const window = getWindow(this.state.elements.popper);
    window.removeEventListener('resize', this.update);

    // Run `onDestroy` modifier methods
    this.state.orderedModifiers.forEach(
      ({ onDestroy, enabled }) => enabled && onDestroy && onDestroy(this.state)
    );
  }
}

Popper.defaultModifiers = [];
<commit_msg>refactor: clean up index.js<commit_after>// @flow
import type {
  JQueryWrapper,
  State,
  Options,
  UpdateCallback,
  EventListeners,
  Rect,
  Modifier,
} from './types';

// DOM Utils
import getElementClientRect from './dom-utils/getElementClientRect';
import listScrollParents from './dom-utils/listScrollParents';
import getWindow from './dom-utils/getWindow';
import getNodeScroll from './dom-utils/getNodeScroll';
import getOffsetParent from './dom-utils/getOffsetParent';

// Pure Utils
import unwrapJqueryElement from './utils/unwrapJqueryElement';
import orderModifiers from './utils/orderModifiers';
import expandToHashMap from './utils/expandToHashMap';
import format from './utils/format';
import debounce from './utils/debounce';
import validateModifiers from './utils/validateModifiers';

const INVALID_ELEMENT_ERROR =
  'Popper: Invalid reference or popper argument provided to Popper, they must be either a valid DOM element or a jQuery-wrapped DOM element.';
const INFINITE_LOOP_ERROR =
  'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.';

const areValidElements = (a: mixed, b: mixed): boolean %checks =>
  a instanceof Element && b instanceof Element;

const defaultOptions = {
  placement: 'bottom',
  eventListeners: { scroll: true, resize: true },
  modifiers: [],
  strategy: 'absolute',
};

export default class Popper {
  static defaultModifiers: Array<Modifier<any>>;
  state: $Shape<State> = {
    placement: 'bottom',
    orderedModifiers: [],
    options: defaultOptions,
    modifiersData: {},
  };

  constructor(
    reference: Element | JQueryWrapper,
    popper: Element | JQueryWrapper,
    options: $Shape<Options> = defaultOptions
  ) {
    // Unwrap `reference` and `popper` elements in case they are
    // wrapped by jQuery, otherwise consume them as is
    const referenceElement = unwrapJqueryElement(reference);
    const popperElement = unwrapJqueryElement(reference);
    this.state.elements = {
      reference: referenceElement,
      popper: popperElement,
    };

    // Store options into state
    this.state.options = { ...defaultOptions, ...options };

    // Don't proceed if `reference` or `popper` are invalid elements
    if (!areValidElements(referenceElement, popperElement)) {
      if (__DEV__) {
        console.error(INVALID_ELEMENT_ERROR);
      }
      return;
    }

    this.state.scrollParents = {
      reference: listScrollParents(referenceElement),
      popper: listScrollParents(popperElement),
    };

    // Validate the provided modifiers so that the consumer will get warned
    // of one of the custom modifiers is invalid for any reason
    if (__DEV__) {
      validateModifiers(this.state.options.modifiers);
    }

    // Order `options.modifiers` so that the dependencies are fulfilled
    // once the modifiers are executed
    this.state.orderedModifiers = orderModifiers([
      ...this.constructor.defaultModifiers,
      ...this.state.options.modifiers,
    ])
      // Apply user defined preferences to modifiers
      .map(modifier => ({
        ...modifier,
        ...this.state.options.modifiers.find(
          ({ name }) => name === modifier.name
        ),
      }));

    // Modifiers have the opportunity to execute some arbitrary code before
    // the first update cycle is ran, the order of execution will be the same
    // defined by the modifier dependencies directive.
    // The `onLoad` function may add or alter the options of themselves
    this.state.orderedModifiers.forEach(
      ({ onLoad, enabled }) => enabled && onLoad && onLoad(this.state)
    );

    this.update().then(() => {
      // After the first update completed, enable the event listeners
      this.enableEventListeners(this.state.options.eventListeners);
    });
  }

  // Async and optimistically optimized update
  // it will not be executed if not necessary
  // debounced, so that it only runs at most once-per-tick
  update = debounce(
    () =>
      new Promise<State>((success, reject) => {
        this.forceUpdate();
        success(this.state);
      })
  );

  // Syncronous and forcefully executed update
  // it will always be executed even if not necessary, usually NOT needed
  // use Popper#update instead
  forceUpdate() {
    const {
      reference: referenceElement,
      popper: popperElement,
    } = this.state.elements;
    // Don't proceed if `reference` or `popper` are not valid elements anymore
    if (!areValidElements(referenceElement, popperElement)) {
      if (__DEV__) {
        console.error(INVALID_ELEMENT_ERROR);
      }
      return;
    }

    // Get initial measurements
    // these are going to be used to compute the initial popper offsets
    // and as cache for any modifier that needs them later
    this.state.measures = {
      reference: getElementClientRect(referenceElement),
      popper: getElementClientRect(popperElement),
    };

    // Get scrollTop and scrollLeft of the offsetParent
    // this will be used in the `computeOffsets` function to properly
    // position the popper taking in account the scroll position
    // FIXME: right now we only look for a single offsetParent (the popper one)
    //        but we really want to take in account the reference offsetParent as well
    const offsetParentScroll = getNodeScroll(getOffsetParent(popperElement));

    // Modifiers have the ability to read the current Popper state, included
    // the popper offsets, and modify it to address specifc cases
    this.state.reset = false;

    // Cache the placement in cache to make it available to the modifiers
    // modifiers will modify this one (rather than the one in options)
    this.state.placement = this.state.options.placement;

    this.state.orderedModifiers.forEach(
      modifier =>
        (this.state.modifiersData[modifier.name] = {
          ...modifier.data,
        })
    );

    let __debug_loops__ = 0;
    for (let index = 0; index < this.state.orderedModifiers.length; index++) {
      if (__DEV__) {
        __debug_loops__ += 1;
        if (__debug_loops__ > 100) {
          console.error(INFINITE_LOOP_ERROR);
          break;
        }
      }

      if (this.state.reset === true) {
        this.state.reset = false;
        index = -1;
        continue;
      }

      const { fn, enabled, options } = this.state.orderedModifiers[index];

      if (enabled && typeof fn === 'function') {
        this.state = fn((this.state: State), options);
      }
    }
  }

  enableEventListeners(
    eventListeners: boolean | {| scroll?: boolean, resize?: boolean |}
  ) {
    const { scroll, resize } =
      typeof eventListeners === 'boolean'
        ? expandToHashMap(eventListeners, ['scroll', 'resize'])
        : eventListeners;

    if (scroll) {
      const scrollParents = [
        ...this.state.scrollParents.reference,
        ...this.state.scrollParents.popper,
      ];

      scrollParents.forEach(scrollParent =>
        scrollParent.addEventListener('scroll', this.update, {
          passive: true,
        })
      );
    }

    if (resize) {
      const window = getWindow(this.state.elements.popper);
      window.addEventListener('resize', this.update, {
        passive: true,
      });
    }
  }

  destroy() {
    // Remove scroll event listeners
    const scrollParents = [
      ...this.state.scrollParents.reference,
      ...this.state.scrollParents.popper,
    ];

    scrollParents.forEach(scrollParent =>
      scrollParent.removeEventListener('scroll', this.update)
    );

    // Remove resize event listeners
    const window = getWindow(this.state.elements.popper);
    window.removeEventListener('resize', this.update);

    // Run `onDestroy` modifier methods
    this.state.orderedModifiers.forEach(
      ({ onDestroy, enabled }) => enabled && onDestroy && onDestroy(this.state)
    );
  }
}

Popper.defaultModifiers = [];
<|endoftext|>


<commit_before>var Snoocore = require('snoocore');
var config = require('../config/config.json');
var TitleFormatPass = require('./passes/TitleFormatPass');
var logger = require('./Logger');

var reddit = new Snoocore({
    userAgent: 'UltraHardcore Flair Checker',
    throttle: 1000,
    oauth: config.login.oauth,
    login: config.login.account
});

var formatPass = new TitleFormatPass(reddit);

logger.info('Starting up database');
require('./db/DbInit')().then(function() {
    return formatPass.removeOld()
}).then(function() {
    logger.info('Authenticating with Reddit');
    return reddit.auth()
}).then(function() {
    logger.info('Fetching reddit posts');
    return reddit('/r/$subreddit/search').get(config.titlePass.query);
}).then(function(results) {
    logger.info('Found %d posts to check', results.data.children.length);
    logger.info('Starting title format check');
    return formatPass.checkPosts(results.data.children);
}).catch(function(err) {
    logger.error('Uncaught error during script: %s', err);
});<commit_msg>refactor(index): move annonymous functions into proper functions<commit_after>var Snoocore = require('snoocore');
var config = require('../config/config.json');
var TitleFormatPass = require('./passes/TitleFormatPass');
var logger = require('./Logger');
var Q = require('q');

var reddit = new Snoocore({
    userAgent: 'UltraHardcore Flair Checker',
    throttle: 1000,
    oauth: config.login.oauth,
    login: config.login.account
});

var formatPass = new TitleFormatPass(reddit);

initDatabase()
    .then(authenticate)
    .then(titlePass)
    .catch(function(err) {
        logger.error('Uncaught error during scripts: %s', err);
    });

/**
 * Pass that works once for each post to check titles. Skips any previously parsed posts
 *
 * @returns {Q.promise}
 */
function titlePass() {
    logger.info('Starting title based pass');
    return reddit('/r/$subreddit/search').get(config.titlePass.query).then(function(results) {
        logger.info('Found %d posts to check', results.data.children.length);

        logger.info('Starting title format check');
        return formatPass.checkPosts(results.data.children);
    });
}

/**
 * Authenticate the account with reddit OAuth
 *
 * @returns {Q.promise}
 */
function authenticate() {
    logger.info('Authenticating with Reddit');

    return reddit.auth();
}

/**
 * Sets up the database and syncs models structure and then removes all the expired post checks from the database
 *
 * @returns {Q.promise}
 */
function initDatabase() {
    logger.info('Starting up database');

    return require('./db/DbInit')()
        .then(formatPass.removeOld)
}<|endoftext|>


<commit_before>import Duration from 'duration'
import shortid from 'shortid'
import moment from 'moment'
import parser from './parser'

export const hashPattern = /(#\w+[\w-]*)/g
export const version = 4
export default class Entry {
  constructor(user, message, opts = {}) {
    let {
      date = new Date(),
    } = opts

    if (typeof message === 'object')
      return this._fromJSON(message)

    this.version = version
    this.user = user
    this._id = shortid.generate()
    this.message = message
    this.ref = date
    this.parse(message, date)
    this.parseTags(message)
  }

  _fromJSON(doc) {
    Object.assign(this, doc)
    const start = new Date(this.start)
    const end = new Date(this.end)
    const text = this.time
    this.setDates({start, end, text})
    this.tags = new Set(doc.tags)
    return this
  }

  parse(msg, date) {
    let d = parser(msg, date)
    if (d.isValid) this.setDates(d)
  }

  parseTags(message) {
    // Set makes things unique
    this.tags = new Set(message.match(hashPattern))
  }

  setDates(opts) {
    this.hasDates = true
    this.start = opts.start
    this.startArr = moment(this.start).utc().toArray()
    this.end = opts.end
    this.endArr = moment(this.end).utc().toArray()
    this.time = opts.text
    this.duration = new Duration(this.start, this.end)
  }

  getDates() {
    let start = this.start
    let end = this.end
    return { start, end }
  }

  toJSON() {
    return {
      _id: this._id,
      version: this.version,
      ref: this.ref,
      user: this.user,
      message: this.message,
      hasDates: this.hasDates,
      start: this.start,
      startArr: this.startArr,
      end: this.end,
      endArr: this.endArr,
      time: this.time,
      tags: [...this.tags],
      duration: this.duration ? {
        seconds: this.duration.seconds,
      } : null
    }
  }

  static fromJSON(doc) {
    let e = new Entry(doc.user, doc)

    return e
  }
}
<commit_msg>save in current version. Resolves #12<commit_after>import Duration from 'duration'
import shortid from 'shortid'
import moment from 'moment'
import parser from './parser'

export const hashPattern = /(#\w+[\w-]*)/g
export const version = 5
export default class Entry {
  constructor(user, message, opts = {}) {
    let {
      date = new Date(),
    } = opts

    if (typeof message === 'object')
      return this._fromJSON(message)

    this.version = version
    this.user = user
    this._id = shortid.generate()
    this.message = message
    this.ref = date
    this.parse(message, date)
    this.parseTags(message)
  }

  _fromJSON(doc) {
    Object.assign(this, doc)
    const start = new Date(this.start)
    const end = new Date(this.end)
    const text = this.time
    this.setDates({start, end, text})
    this.tags = new Set(doc.tags)
    return this
  }

  parse(msg, date) {
    let d = parser(msg, date)
    if (d.isValid) this.setDates(d)
  }

  parseTags(message) {
    // Set makes things unique
    this.tags = new Set(message.match(hashPattern))
  }

  setDates(opts) {
    this.hasDates = true
    this.start = opts.start
    this.startArr = moment(this.start).utc().toArray()
    this.end = opts.end
    this.endArr = moment(this.end).utc().toArray()
    this.time = opts.text
    this.duration = new Duration(this.start, this.end)
  }

  getDates() {
    let start = this.start
    let end = this.end
    return { start, end }
  }

  toJSON() {
    return {
      _id: this._id,
      version: this.version,
      ref: this.ref,
      user: this.user,
      message: this.message,
      hasDates: this.hasDates,
      start: this.start,
      startArr: this.startArr,
      end: this.end,
      endArr: this.endArr,
      time: this.time,
      tags: [...this.tags],
      duration: this.duration ? {
        seconds: this.duration.seconds,
      } : null
    }
  }

  static fromJSON(doc) {
    let e = new Entry(doc.user, doc)

    return e
  }
}
<|endoftext|>


<commit_before>import Discordie from 'discordie';
import chalk from 'chalk';
import moment from 'moment';
import nconf from 'nconf';
import R from 'ramda';

import './init-config';
import './express';
import './sentry';
import './phantom';
import commands from './commands';

import { getUserLang } from './redis';

// Init
const client = new Discordie();

function callCmd(cmd, name, client, e, suffix) {
  console.log(`${chalk.blue('[' + moment().format('HH:mm:ss' + ']'))} ${chalk.bold.green(name)}: ${suffix}`);
  getUserLang(e.message.author.id).then(lang => {
    cmd(client, e, suffix, lang);
  });
}

function onMessage(e) {
  if (client.User.id === e.message.author.id) return;

  // Checks for PREFIX
  if (e.message.content[0] === nconf.get('PREFIX')) {
    let command = e.message.content.toLowerCase().split(' ')[0].substring(1);
    let suffix = e.message.content.substring(command.length + 2);
    let cmd = commands[command];

    if (cmd) callCmd(cmd, command, client, e, suffix);
    return;
  }

  // Checks if bot was mentioned
  if (client.User.isMentioned(e.message)) {
    let msg_split = e.message.content.split(' ');

    // If bot was mentioned without a command, then skip.
    if (!msg_split[1]) return;

    let suffix = R.join(' ', R.slice(2, msg_split.length, msg_split));
    let cmd_name = msg_split[1].toLowerCase();
    if (cmd_name[0] === nconf.get('PREFIX')) cmd_name = cmd_name.slice(1);
    let cmd = commands[cmd_name];

    if (cmd) callCmd(cmd, cmd_name, client, e, suffix);
    return;
  }

  // Check personal messages
  if (e.message.channel.is_private) {
    // Handle invite links
    if (e.message.content.indexOf('https://discord.gg/') > -1 || e.message.content.indexOf('https://discordapp.com/invite/') > -1) {
      return commands.join(client, e, e.message.content);
    }

    let msg_split = e.message.content.split(' ');
    let suffix = R.join(' ', R.slice(1, msg_split.length, msg_split));
    let cmd_name = msg_split[0].toLowerCase();
    let cmd = commands[cmd_name];

    if (cmd) callCmd(cmd, cmd_name, client, e, suffix);
    return;
  }
}

function connect() {
  if (!nconf.get('TOKEN')) {
    console.error('Please setup TOKEN or EMAIL and PASSWORD in config.js to use Gravebot');
    process.exit(1);
  }

  client.connect({token: nconf.get('TOKEN')});
}

// Listen for events on Discord
client.Dispatcher.on('GATEWAY_READY', e => {
  client.Users.fetchMembers();
  console.log(chalk.green(`[${moment().format('YYYY-MM-DD HH:mm:ss')}] Started successfully. Connected to ${client.Guilds.length} servers.`));
});

client.Dispatcher.on('DISCONNECTED', e => {
  console.log(chalk.yellow(`[${moment().format('YYYY-MM-DD HH:mm:ss')}] Disconnected. Attempting to reconnect...`));
  setTimeout(() => {
    connect();
  }, 2000);
});

client.Dispatcher.on('MESSAGE_CREATE', onMessage);
client.Dispatcher.on('MESSAGE_UPDATE', onMessage);

connect();
<commit_msg>update error message<commit_after>import Discordie from 'discordie';
import chalk from 'chalk';
import moment from 'moment';
import nconf from 'nconf';
import R from 'ramda';

import './init-config';
import './express';
import './sentry';
import './phantom';
import commands from './commands';

import { getUserLang } from './redis';

// Init
const client = new Discordie();

function callCmd(cmd, name, client, e, suffix) {
  console.log(`${chalk.blue('[' + moment().format('HH:mm:ss' + ']'))} ${chalk.bold.green(name)}: ${suffix}`);
  getUserLang(e.message.author.id).then(lang => {
    cmd(client, e, suffix, lang);
  });
}

function onMessage(e) {
  if (client.User.id === e.message.author.id) return;

  // Checks for PREFIX
  if (e.message.content[0] === nconf.get('PREFIX')) {
    let command = e.message.content.toLowerCase().split(' ')[0].substring(1);
    let suffix = e.message.content.substring(command.length + 2);
    let cmd = commands[command];

    if (cmd) callCmd(cmd, command, client, e, suffix);
    return;
  }

  // Checks if bot was mentioned
  if (client.User.isMentioned(e.message)) {
    let msg_split = e.message.content.split(' ');

    // If bot was mentioned without a command, then skip.
    if (!msg_split[1]) return;

    let suffix = R.join(' ', R.slice(2, msg_split.length, msg_split));
    let cmd_name = msg_split[1].toLowerCase();
    if (cmd_name[0] === nconf.get('PREFIX')) cmd_name = cmd_name.slice(1);
    let cmd = commands[cmd_name];

    if (cmd) callCmd(cmd, cmd_name, client, e, suffix);
    return;
  }

  // Check personal messages
  if (e.message.channel.is_private) {
    // Handle invite links
    if (e.message.content.indexOf('https://discord.gg/') > -1 || e.message.content.indexOf('https://discordapp.com/invite/') > -1) {
      return commands.join(client, e, e.message.content);
    }

    let msg_split = e.message.content.split(' ');
    let suffix = R.join(' ', R.slice(1, msg_split.length, msg_split));
    let cmd_name = msg_split[0].toLowerCase();
    let cmd = commands[cmd_name];

    if (cmd) callCmd(cmd, cmd_name, client, e, suffix);
    return;
  }
}

function connect() {
  if (!nconf.get('TOKEN')) {
    console.error('Please setup TOKEN in config.js to use Gravebot');
    process.exit(1);
  }

  client.connect({token: nconf.get('TOKEN')});
}

// Listen for events on Discord
client.Dispatcher.on('GATEWAY_READY', e => {
  client.Users.fetchMembers();
  console.log(chalk.green(`[${moment().format('YYYY-MM-DD HH:mm:ss')}] Started successfully. Connected to ${client.Guilds.length} servers.`));
});

client.Dispatcher.on('DISCONNECTED', e => {
  console.log(chalk.yellow(`[${moment().format('YYYY-MM-DD HH:mm:ss')}] Disconnected. Attempting to reconnect...`));
  setTimeout(() => {
    connect();
  }, 2000);
});

client.Dispatcher.on('MESSAGE_CREATE', onMessage);
client.Dispatcher.on('MESSAGE_UPDATE', onMessage);

connect();
<|endoftext|>


<commit_before>import React from 'react';
import { render } from 'react-dom';

const CurrentAction = props => {
    const { action } = props;
    const text = action ? action.minute + "分 " + action.name + (action.note ? " (" + action.note + ")" : "") : "";
    return (

現: {text}

    );
};

const NextAction = props => {
    const { action, date } = props;
    const text = (() => {
        if (action) {
            const { name, minute } = action;
            const m = date.getMinutes();
            const s = date.getSeconds();
            const restMinute = minute - m - (s == 0 ? 0 : 1);
            const restSeconds = s == 0 ? 0 : 60 - s;
            return minute + "分 " + name + " (" + restMinute + ":" + ("0" + restSeconds).slice(-2) + ")"
        } else {
            return "";
        }
    })();

    return (

次: {text}

    );
}

const Exceeds = props => {
    const { data, date } = props;

    const extract = (data, date) => {
        const minute = date.getMinutes();
        const actions = data.actions;

        var i = 0;
        while (i < actions.length && actions[i].minute <= minute) i++;

        const current = 0 <= i - 1 && i - 1 < actions.length ? actions[i - 1] : undefined;
        const next = 0 <= i && i < actions.length ? actions[i] : undefined;

        return { current, next };
    };

    const { current, next } = extract(data, date);

    return (

{data.title}

現在時刻: {date.toLocaleTimeString()}

            <CurrentAction action={current} />
            <NextAction action={next} date={date} />

    );
};

setInterval(() => {
    const date = new Date();
    render(<Exceeds data={data} date={date} />, document.getElementById('app'));
}, 100);
<commit_msg>varをletに変更<commit_after>import React from 'react';
import { render } from 'react-dom';

const CurrentAction = props => {
    const { action } = props;
    const text = action ? action.minute + "分 " + action.name + (action.note ? " (" + action.note + ")" : "") : "";
    return (

現: {text}

    );
};

const NextAction = props => {
    const { action, date } = props;
    const text = (() => {
        if (action) {
            const { name, minute } = action;
            const m = date.getMinutes();
            const s = date.getSeconds();
            const restMinute = minute - m - (s == 0 ? 0 : 1);
            const restSeconds = s == 0 ? 0 : 60 - s;
            return minute + "分 " + name + " (" + restMinute + ":" + ("0" + restSeconds).slice(-2) + ")"
        } else {
            return "";
        }
    })();

    return (

次: {text}

    );
}

const Exceeds = props => {
    const { data, date } = props;

    const extract = (data, date) => {
        const minute = date.getMinutes();
        const actions = data.actions;

        let i = 0;
        while (i < actions.length && actions[i].minute <= minute) i++;

        const current = 0 <= i - 1 && i - 1 < actions.length ? actions[i - 1] : undefined;
        const next = 0 <= i && i < actions.length ? actions[i] : undefined;

        return { current, next };
    };

    const { current, next } = extract(data, date);

    return (

{data.title}

現在時刻: {date.toLocaleTimeString()}

            <CurrentAction action={current} />
            <NextAction action={next} date={date} />

    );
};

setInterval(() => {
    const date = new Date();
    render(<Exceeds data={data} date={date} />, document.getElementById('app'));
}, 100);
<|endoftext|>


<commit_before>import * as inode from "./inode";

import { seq, first } from "./seq";

import { Parser } from "./parser";

import * as array from "./array";

import * as map from "./map";

// TODO move to better location
// TODO update when loader spec is solid
// TODO add easy access to a xhr / db module
import { readFileSync, readdirSync } from "fs";

export function parseString(str, cb) {
	var parser = new Parser(inode);
	return parser.parseString(str, cb);
}

export function parse($a){
	var xml = first($a);
	var result;
	parseString(xml,function(err,ret){
		if(err) console.log(err);
		result = ret;
	});
	return result;
}

export function doc($file){
	var file = first($file);
	return parse(readFileSync(file.toString(),"utf-8"));
}

export function collection($uri) {
	var uri = first($uri);
	return seq(readdirSync(uri).map(file => doc(uri+"/"+file)));
}

export * from "./doc";

export * from "./construct";

export * from "./qname";

export * from "./modify";

export * from "./access";

export * from "./l3";

export { fromJS, toJS, iter as iterJS, toL3 as jsToL3, fromL3 as jsFromL3 } from "./json";

export * from "./seq";

export * from "./subseq";

export * from "./type";

export * from "./string";

export * from "./function";

export * from "./op";

export * from "./validate";

//export { array, map};
<commit_msg>removed nodeenv checks to fs, fixed doc<commit_after>import * as inode from "./inode";

import { zeroOrOne, create } from "./seq";

import { Parser } from "./parser";

import { readdir, readFile } from "./fs";

import { isNodeEnv } from "./util";

if(isNodeEnv() && !global.URL) {
	let url = require("url");
	global.URL = url.URL;
}

export function parseString(str, cb) {
	var parser = new Parser(inode);
	return parser.parseString(str, cb);
}

export function parse($s){
	return zeroOrOne($s).concatMap(s => create(o => {
		parseString(s,function(err,ret){
			if(err) return o.error(err);
			o.next(ret);
			o.complete();
		});
	})).share();
}

export function doc($file){
	return zeroOrOne($file).concatMap(file => create(o => {
		readFile(file.toString(),(err, res) => {
			if(err) return o.error(err);
			parse(res).subscribe({
				next:x => o.next(x),
				error: err => o.error(err),
				complete: () => o.complete()
			});
		});
	})).share();
}

export function collection($uri) {
	return zeroOrOne($uri).concatMap(uri => create(o => {
		readdir(uri,function(err,res){
			if(err) return o.error(err);
			res.forEach(file => {
				doc(uri+"/"+file).subscribe({
					next: x => o.next(x),
					error: err => o.error(err)
				});
			});
			o.complete();
		});
	})).share();
}

export * from "./doc";

export * from "./construct";

export * from "./qname";

export * from "./modify";

export * from "./access";

export * from "./l3";

export { fromJS, toJS, iter as iterJS, toL3 as jsToL3, fromL3 as jsFromL3 } from "./json";

export * from "./seq";

export * from "./subseq";

export * from "./type";

export * from "./string";

export * from "./function";

export * from "./op";

export * from "./validate";
<|endoftext|>


<commit_before>export * as common from './common';
export * as fees from './fees';
export * as pmc from './pmc';
export * as taxes from './taxes';
export * as units from './units';
<commit_msg>missing export<commit_after>export * as common from './common';
export * as fees from './fees';
export * as pmc from './pmc';
export * as taxes from './taxes';
export * as units from './units';
export * as availability from './availability';
<|endoftext|>


<commit_before>import log from 'apify-shared/log';
import { ENV_VARS } from 'apify-shared/consts';
import { main, getEnv, call, getApifyProxyUrl } from './actor';
import AutoscaledPool from './autoscaling/autoscaled_pool';
import BasicCrawler from './basic_crawler';
import CheerioCrawler from './cheerio_crawler';
import { pushData, openDataset } from './dataset';
import events, { initializeEvents, stopEvents } from './events';
import { getValue, setValue, openKeyValueStore } from './key_value_store';
import { launchPuppeteer } from './puppeteer';
import PuppeteerCrawler from './puppeteer_crawler';
import PuppeteerPool from './puppeteer_pool';
import Request from './request';
import RequestList from './request_list';
import { openRequestQueue } from './request_queue';
import SettingsRotator from './settings_rotator';
import { apifyClient, getMemoryInfo, isProduction, isAtHome, publicUtils } from './utils';
import { browse, launchWebDriver } from './webdriver';
import { puppeteerUtils } from './puppeteer_utils';
import PseudoUrl from './pseudo_url';

/* globals module */

// Hide debug log messages when running in production mode.
if (!isProduction() || process.env[ENV_VARS.LOG_LEVEL] === 'DEBUG') log.isDebugMode = true;

// Log as plain text not JSON
log.logJson = false;

// TODO: remove this when we release v1.0.0
const EMULATION_ENV_VAR = 'APIFY_LOCAL_EMULATION_DIR';
if (process.env[EMULATION_ENV_VAR]) {
    log.warning(`Environment variable "${EMULATION_ENV_VAR}" is deprecated!!! Use "${ENV_VARS.LOCAL_STORAGE_DIR}" instead!`);
    if (!process.env[ENV_VARS.LOCAL_STORAGE_DIR]) process.env[ENV_VARS.LOCAL_STORAGE_DIR] = process.env[EMULATION_ENV_VAR];
}

/**
 *{include-readme-1}
 *{include-readme-2}
 *{include-readme-3}
 *
 *
Programmer's reference

 *
 * The following sections describe all functions and properties provided by the `apify` package.
 * All of them are instance members exported directly by the main module.
 *
 * @module Apify
 */
module.exports = {
    // Actor
    main,
    getEnv,
    call,
    getMemoryInfo,
    getApifyProxyUrl,
    isAtHome,
    client: apifyClient,

    // Autoscaled pool
    AutoscaledPool,

    // Basic crawler
    BasicCrawler,

    // Cheerio crawler
    CheerioCrawler,

    // Dataset
    pushData,
    openDataset,

    // Events
    events,
    initializeEvents,
    stopEvents,

    // Key-value store
    getValue,
    setValue,
    openKeyValueStore,

    // Puppeteer
    launchPuppeteer,
    PuppeteerPool,
    PuppeteerCrawler,

    // PseudoUrl
    PseudoUrl,

    // Requests
    Request,
    RequestList,
    openRequestQueue,

    // Settings rotator
    SettingsRotator,

    // Webdriver
    browse,
    launchWebDriver,

    // utils
    utils: Object.assign(publicUtils, {
        puppeteer: puppeteerUtils,
        log,
    }),
};
<commit_msg>Setting log level to INFO by default<commit_after>import log from 'apify-shared/log';
import { ENV_VARS } from 'apify-shared/consts';
import { main, getEnv, call, getApifyProxyUrl } from './actor';
import AutoscaledPool from './autoscaling/autoscaled_pool';
import BasicCrawler from './basic_crawler';
import CheerioCrawler from './cheerio_crawler';
import { pushData, openDataset } from './dataset';
import events, { initializeEvents, stopEvents } from './events';
import { getValue, setValue, openKeyValueStore } from './key_value_store';
import { launchPuppeteer } from './puppeteer';
import PuppeteerCrawler from './puppeteer_crawler';
import PuppeteerPool from './puppeteer_pool';
import Request from './request';
import RequestList from './request_list';
import { openRequestQueue } from './request_queue';
import SettingsRotator from './settings_rotator';
import { apifyClient, getMemoryInfo, isProduction, isAtHome, publicUtils } from './utils';
import { browse, launchWebDriver } from './webdriver';
import { puppeteerUtils } from './puppeteer_utils';
import PseudoUrl from './pseudo_url';

/* globals module */

// Log as plain text not JSON
log.logJson = false;

// TODO: remove this when we release v1.0.0
const EMULATION_ENV_VAR = 'APIFY_LOCAL_EMULATION_DIR';
if (process.env[EMULATION_ENV_VAR]) {
    log.warning(`Environment variable "${EMULATION_ENV_VAR}" is deprecated!!! Use "${ENV_VARS.LOCAL_STORAGE_DIR}" instead!`);
    if (!process.env[ENV_VARS.LOCAL_STORAGE_DIR]) process.env[ENV_VARS.LOCAL_STORAGE_DIR] = process.env[EMULATION_ENV_VAR];
}

/**
 *{include-readme-1}
 *{include-readme-2}
 *{include-readme-3}
 *
 *
Programmer's reference

 *
 * The following sections describe all functions and properties provided by the `apify` package.
 * All of them are instance members exported directly by the main module.
 *
 * @module Apify
 */
module.exports = {
    // Actor
    main,
    getEnv,
    call,
    getMemoryInfo,
    getApifyProxyUrl,
    isAtHome,
    client: apifyClient,

    // Autoscaled pool
    AutoscaledPool,

    // Basic crawler
    BasicCrawler,

    // Cheerio crawler
    CheerioCrawler,

    // Dataset
    pushData,
    openDataset,

    // Events
    events,
    initializeEvents,
    stopEvents,

    // Key-value store
    getValue,
    setValue,
    openKeyValueStore,

    // Puppeteer
    launchPuppeteer,
    PuppeteerPool,
    PuppeteerCrawler,

    // PseudoUrl
    PseudoUrl,

    // Requests
    Request,
    RequestList,
    openRequestQueue,

    // Settings rotator
    SettingsRotator,

    // Webdriver
    browse,
    launchWebDriver,

    // utils
    utils: Object.assign(publicUtils, {
        puppeteer: puppeteerUtils,
        log,
    }),
};
<|endoftext|>


<commit_before>import tagNames from 'html-tag-names'

const isValidString =
  param =>
    typeof param === 'string' && param.length > 0;

const startsWith =
  (string, start) =>
    string[0] === start;

const isSelector =
  param =>
    isValidString(param) && (startsWith(param, '.') || startsWith(param, '#'));

const node =
  h =>
    tagName =>
      (first, ...rest) => {
        if (isSelector(first)) {
          return h(tagName + first, ...rest);
        } else if (typeof first === 'undefined') {
          return h(tagName);
        } else {
          return h(tagName, first, ...rest);
        }
      };

export default
  h => {
    const createTag = node(h);
    const exported = { tagNames, isSelector, createTag };
    tagNames.forEach(n => {
      exported[n] = createTag(n);
    });
    return exported;
  };
<commit_msg>fix linting<commit_after>import tagNames from 'html-tag-names';

const isValidString =
  param =>
    typeof param === 'string' && param.length > 0;

const startsWith =
  (string, start) =>
    string[0] === start;

const isSelector =
  param =>
    isValidString(param) && (startsWith(param, '.') || startsWith(param, '#'));

const node =
  h =>
    tagName =>
      (first, ...rest) => {
        if (isSelector(first)) {
          return h(tagName + first, ...rest);
        } else if (typeof first === 'undefined') {
          return h(tagName);
        } else {
          return h(tagName, first, ...rest);
        }
      };

export default
  h => {
    const createTag = node(h);
    const exported = { tagNames, isSelector, createTag };
    tagNames.forEach(n => {
      exported[n] = createTag(n);
    });
    return exported;
  };
<|endoftext|>


<commit_before>import React from "react"
import ReactDOM from "react-dom"
import Raven from "raven-js"
import createRavenMiddleware from "raven-for-redux"
import { Provider } from "react-redux"
import { createStore, applyMiddleware, compose } from "redux"
import { Route, Switch, Redirect } from "react-router-dom"
import { routerMiddleware, ConnectedRouter } from "react-router-redux"
import { createBrowserHistory } from "history"
import NotificationSystem from "react-notification-system"

// CSS
import "semantic-ui-css/semantic.min.css";
import "react-select/dist/react-select.css"
import "rc-slider/assets/index.css";

// Redux
import App from "./reducers"
import api from "./services/api"
import persist from "./services/persist"
import notification from "./services/notification"

// Containers
import Full from "./containers/Full/"
import Login from "./containers/Login"

// Actions
import { requestServlets, requestCheckUser } from "./actions"
import { saveNotifRef } from "./actions/notification"

// Sentry
Raven.config("https://61d75957355b4aa486ff8653dc64acd0@sentry.io/203544").install()

const history = createBrowserHistory({
	basename: "/admin",
});

// Try and reconstruct state
let initialState = undefined;
if (window.localStorage) {
	const prevApi = window.localStorage.getItem("api");
	initialState = {
		api: prevApi ? JSON.parse(prevApi) : undefined,
	};
}

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
let store = createStore(
	App,
	initialState,
	composeEnhancers(
		applyMiddleware(
			api,
			persist,
			notification,
			routerMiddleware(history),
			createRavenMiddleware(Raven, {})
		)
	)
);

// Check if the possibly saved state/key is still valid
if (store.getState().api.loggedIn) {
	store.dispatch(requestCheckUser());
}

store.dispatch(requestServlets());

class Main extends React.Component {
	render() {
		return

			<Provider store={store}>
				<ConnectedRouter history={history} basename="/admin">
					<Switch>
						<Route path="/login" name="Login" component={Login} />
						<Route path="/" name="Home" render={props => {
							if (store.getState().api.loggedIn)
								return <Full {...props} />
							else
								return <Redirect to={{ pathname: "/login", state: { from: props.location }}} />
						}} />
					</Switch>
				</ConnectedRouter>
			</Provider>
			<NotificationSystem ref={ref => store.dispatch(saveNotifRef(ref))} />

	}
}

ReactDOM.render(, document.getElementById("root"))
<commit_msg>feat(sentry): Add admin-panel version<commit_after>import React from "react"
import ReactDOM from "react-dom"
import Raven from "raven-js"
import createRavenMiddleware from "raven-for-redux"
import { Provider } from "react-redux"
import { createStore, applyMiddleware, compose } from "redux"
import { Route, Switch, Redirect } from "react-router-dom"
import { routerMiddleware, ConnectedRouter } from "react-router-redux"
import { createBrowserHistory } from "history"
import NotificationSystem from "react-notification-system"
import pkg from "../package.json"

// CSS
import "semantic-ui-css/semantic.min.css";
import "react-select/dist/react-select.css"
import "rc-slider/assets/index.css";

// Redux
import App from "./reducers"
import api from "./services/api"
import persist from "./services/persist"
import notification from "./services/notification"

// Containers
import Full from "./containers/Full/"
import Login from "./containers/Login"

// Actions
import { requestServlets, requestCheckUser } from "./actions"
import { saveNotifRef } from "./actions/notification"

// Sentry
Raven.config("https://61d75957355b4aa486ff8653dc64acd0@sentry.io/203544").install()
Raven.setTagsContext({ release: pkg.version });

const history = createBrowserHistory({
	basename: "/admin",
});

// Try and reconstruct state
let initialState = undefined;
if (window.localStorage) {
	const prevApi = window.localStorage.getItem("api");
	initialState = {
		api: prevApi ? JSON.parse(prevApi) : undefined,
	};
}

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
let store = createStore(
	App,
	initialState,
	composeEnhancers(
		applyMiddleware(
			api,
			persist,
			notification,
			routerMiddleware(history),
			createRavenMiddleware(Raven, {})
		)
	)
);

// Check if the possibly saved state/key is still valid
if (store.getState().api.loggedIn) {
	store.dispatch(requestCheckUser());
}

store.dispatch(requestServlets());

class Main extends React.Component {
	render() {
		return

			<Provider store={store}>
				<ConnectedRouter history={history} basename="/admin">
					<Switch>
						<Route path="/login" name="Login" component={Login} />
						<Route path="/" name="Home" render={props => {
							if (store.getState().api.loggedIn)
								return <Full {...props} />
							else
								return <Redirect to={{ pathname: "/login", state: { from: props.location }}} />
						}} />
					</Switch>
				</ConnectedRouter>
			</Provider>
			<NotificationSystem ref={ref => store.dispatch(saveNotifRef(ref))} />

	}
}

ReactDOM.render(, document.getElementById("root"))
<|endoftext|>