text: import { Tweenable } from './tweenable'
  
  /**
   * The Bezier magic in this file is adapted/copied almost wholesale from
   * [Scripty2](https://github.com/madrobby/scripty2/blob/master/src/effects/transitions/cubic-bezier.js),
   * which was adapted from Apple code (which probably came from
   * [here](http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h)).
   * Special thanks to Apple and Thomas Fuchs for much of this code.
   */
  
  /**
   *  Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions are met:
   *
   *  1. Redistributions of source code must retain the above copyright notice,
   *  this list of conditions and the following disclaimer.
   *
   *  2. Redistributions in binary form must reproduce the above copyright notice,
   *  this list of conditions and the following disclaimer in the documentation
   *  and/or other materials provided with the distribution.
   *
   *  3. Neither the name of the copyright holder(s) nor the names of any
   *  contributors may be used to endorse or promote products derived from
   *  this software without specific prior written permission.
   *
   *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   *  POSSIBILITY OF SUCH DAMAGE.
   */
  // port of webkit cubic bezier handling by http://www.netzgesta.de/dev/
  
  /**
   * @param {number} t
   * @param {number} p1x
   * @param {number} p1y
   * @param {number} p2x
   * @param {number} p2y
   * @param {number} duration
   * @returns {Function}
   * @private
   */
  function cubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) {
    let ax = 0,
      bx = 0,
      cx = 0,
      ay = 0,
      by = 0,
      cy = 0
  
    const sampleCurveX = t => ((ax * t + bx) * t + cx) * t
  
    const sampleCurveY = t => ((ay * t + by) * t + cy) * t
  
    const sampleCurveDerivativeX = t => (3 * ax * t + 2 * bx) * t + cx
  
    const solveEpsilon = duration => 1 / (200 * duration)
  
    const fabs = n => (n >= 0 ? n : 0 - n)
  
    const solveCurveX = (x, epsilon) => {
      let t0, t1, t2, x2, d2, i
  
      for (t2 = x, i = 0; i < 8; i++) {
        x2 = sampleCurveX(t2) - x
  
        if (fabs(x2) < epsilon) {
          return t2
        }
  
        d2 = sampleCurveDerivativeX(t2)
  
        if (fabs(d2) < 1e-6) {
          break
        }
  
        t2 = t2 - x2 / d2
      }
  
      t0 = 0
      t1 = 1
      t2 = x
  
      if (t2 < t0) {
        return t0
      }
  
      if (t2 > t1) {
        return t1
      }
  
      while (t0 < t1) {
        x2 = sampleCurveX(t2)
  
        if (fabs(x2 - x) < epsilon) {
          return t2
        }
  
        if (x > x2) {
          t0 = t2
        } else {
          t1 = t2
        }
  
        t2 = (t1 - t0) * 0.5 + t0
      }
  
      return t2 // Failure.
    }
  
    const solve = (x, epsilon) => sampleCurveY(solveCurveX(x, epsilon))
  
    cx = 3 * p1x
    bx = 3 * (p2x - p1x) - cx
    ax = 1 - cx - bx
    cy = 3 * p1y
    by = 3 * (p2y - p1y) - cy
    ay = 1 - cy - by
  
    return solve(t, solveEpsilon(duration))
  }
  // End ported code
  
  /**
   *  GetCubicBezierTransition(x1, y1, x2, y2) -> Function.
   *
   *  Generates a transition easing function that is compatible
   *  with WebKit's CSS transitions `-webkit-transition-timing-function`
   *  CSS property.
   *
   *  The W3C has more information about CSS3 transition timing functions:
   *  http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
   *
   *  @param {number} x1
   *  @param {number} y1
   *  @param {number} x2
   *  @param {number} y2
   *  @return {Function}
   *  @private
   */
  const getCubicBezierTransition = (x1, y1, x2, y2) => pos =>
    cubicBezierAtTime(pos, x1, y1, x2, y2, 1)
  
  /**
   * Create a Bezier easing function and attach it to {@link
   * shifty.Tweenable.formulas}.  This function gives you total control over the
   * easing curve.  Matthew Lein's [Ceaser](http://matthewlein.com/ceaser/) is a
   * useful tool for visualizing the curves you can make with this function.
   * @method shifty.setBezierFunction
   * @param {string} name The name of the easing curve.  Overwrites the old
   * easing function on {@link shifty.Tweenable.formulas} if it exists.
   * @param {number} x1
   * @param {number} y1
   * @param {number} x2
   * @param {number} y2
   * @return {shifty.easingFunction} The {@link shifty.easingFunction} that was
   * attached to {@link shifty.Tweenable.formulas}.
   */
  export const setBezierFunction = (name, x1, y1, x2, y2) => {
    const cubicBezierTransition = getCubicBezierTransition(x1, y1, x2, y2)
  
    cubicBezierTransition.displayName = name
    cubicBezierTransition.x1 = x1
    cubicBezierTransition.y1 = y1
    cubicBezierTransition.x2 = x2
    cubicBezierTransition.y2 = y2
  
    return (Tweenable.formulas[name] = cubicBezierTransition)
  }
  
  /**
   * `delete` an easing function from {@link shifty.Tweenable.formulas}.  Be
   * careful with this method, as it `delete`s whatever easing formula matches
   * `name` (which means you can delete standard Shifty easing functions).
   * @method shifty.unsetBezierFunction
   * @param {string} name The name of the easing function to delete.
   * @return {boolean} Whether or not the functions was `delete`d.
   */
  export const unsetBezierFunction = name => delete Tweenable.formulas[name]
  