     case .out:
       return (x: x, y: y, scaleX: scaleX, scaleY: scaleY)
     }
-    
-  }
-  
-  public func slide(_ way: AnimationType.Way, direction: AnimationType.Direction, completion: AnimatableCompletion? = nil) {
-
-    let values = computeValues(way: way, direction: direction, shouldScale: false)
-    switch way {
-    case .in:
-      animateIn(values.x, values.y, values.scaleX, values.scaleY, 1, completion)
-    case .out:
-      animateOut(values.x, values.y, values.scaleX, values.scaleY, 1, completion)
-    }
-  }
-  
-  
-  public func squeeze(_ way: AnimationType.Way, direction: AnimationType.Direction, completion: AnimatableCompletion? = nil) {
-  
-    let values = computeValues(way: way, direction: direction, shouldScale: true)
-    switch way {
-    case .in:
-      animateIn(values.x, values.y, values.scaleX, values.scaleY, 1, completion)
-    case .out:
-      animateOut(values.x, values.y, values.scaleX, values.scaleY, 1, completion)
-    }
-  }
-  
-  public func rotate(direction: AnimationType.RotationDirection, repeatCount: Int, completion: AnimatableCompletion? = nil) {
-  
-    CALayer.animate({
-      let animation = CABasicAnimation(keyPath: "transform.rotation")
-      animation.fromValue = direction == .cw ? 0 : CGFloat.pi * 2
-      animation.toValue = direction == .cw  ? CGFloat.pi * 2 : 0
-      animation.duration = CFTimeInterval(self.duration)
-      animation.repeatCount = Float(repeatCount)
-      animation.autoreverses = false
-      animation.beginTime = CACurrentMediaTime() + CFTimeInterval(self.delay)
-      self.layer.add(animation, forKey: "rotate")
-      }, completion: completion)
-
-  }
-  
-  public func moveTo(x: Double, y: Double, completion: AnimatableCompletion? = nil) {
-    if x.isNaN && y.isNaN {
-      return
-    }
-    // Get the absolute position
-    let absolutePosition = convert(frame.origin, to: nil)
-    var xOffsetToMove: CGFloat
-    if x.isNaN {
-      xOffsetToMove = 0
-    } else {
-      xOffsetToMove = CGFloat(x) - absolutePosition.x
-    }
-    
-    var yOffsetToMove: CGFloat
-    if y.isNaN {
-      yOffsetToMove = 0
-    } else {
-      yOffsetToMove = CGFloat(y) - absolutePosition.y
-    }
-      animateBy(x: xOffsetToMove, y: yOffsetToMove, completion: completion)
-  }
-  
-  public func slideFade(_ way: AnimationType.Way, direction: AnimationType.Direction, completion: AnimatableCompletion? = nil) {
-    
-    let values = computeValues(way: way, direction: direction, shouldScale: false)
-    switch way {
-    case .in:
-      alpha = 0
-      animateIn(values.x, values.y, values.scaleX, values.scaleY, 1, completion)
-    case .out:
-      animateOut(values.x, values.y, values.scaleX, values.scaleY, 0, completion)
-    }
-  }
-  
-  public func fade(_ way: AnimationType.FadeWay, completion: AnimatableCompletion? = nil) {
-    switch way {
-    case .outIn:
-      fadeOutIn(completion: completion)
-    case .inOut:
-      fadeInOut(completion: completion)
-    case .in:
-      alpha = 0
-      animateIn(0, 0, 1, 1, 1, completion)
-    case .out:
-      alpha = 1
-      animateOut(0, 0, 1, 1, 0, completion)
-    }
-  }
-  
-  public func squeezeFade(_ way: AnimationType.Way, direction: AnimationType.Direction, completion: AnimatableCompletion? = nil) {
-    
-    let values = computeValues(way: way, direction: direction, shouldScale: true)
-    switch way {
-    case .in:
-      alpha = 0
-      animateIn(values.x, values.y, values.scaleX, values.scaleY, 1, completion)
-    case .out:
-      animateOut(values.x, values.y, values.scaleX, values.scaleY, 0, completion)
-    }
-  }
-  
-  public func zoom(_ way: AnimationType.Way, invert: Bool = false, completion: AnimatableCompletion? = nil) {
-    let toAlpha: CGFloat
-
-    switch way {
-    case .in where invert:
-      let scale = force
-      alpha = 0
-      toAlpha = 1
-      transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
-      animateIn(0, 0, scale / 2, scale / 2, toAlpha, completion)
-    case .in:
-      let scale = 2 * force
-      alpha = 0
-      toAlpha = 1
-      animateIn(0, 0, scale, scale, toAlpha, completion)
-    case .out:
-      let scale = (invert ? 0.1 :  2) * force
-      alpha = 1
-      toAlpha = 0
-      animateOut(0, 0, scale, scale, toAlpha, completion)
-    }
-  }
-  
-  public func flip(axis: AnimationType.Axis, completion: AnimatableCompletion? = nil) {
-    let scaleX: CGFloat
-    let scaleY: CGFloat
-    switch axis {
-    case .x:
-      scaleX = 1
-      scaleY = -1
-    case .y:
-      scaleX = -1
-      scaleY = 1
-    }
-    animateIn(0, 0, scaleX, scaleY, 1, completion)
-  }
-  
-  public func shake(repeatCount: Int, completion: AnimatableCompletion? = nil) {
-    CALayer.animate({
-      let animation = CAKeyframeAnimation(keyPath: "position.x")
-      animation.values = [0, 30 * self.force, -30 * self.force, 30 * self.force, 0]
-      animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-      animation.duration = CFTimeInterval(self.duration)
-      animation.isAdditive = true
-      animation.repeatCount = Float(repeatCount)
-      animation.beginTime = CACurrentMediaTime() + CFTimeInterval(self.delay)
-      self.layer.add(animation, forKey: "shake")
-    }, completion: completion)
-  }
-  
-  public func pop(repeatCount: Int, completion: AnimatableCompletion? = nil) {
-    CALayer.animate({
-      let animation = CAKeyframeAnimation(keyPath: "transform.scale")
-      animation.values = [0, 0.2 * self.force, -0.2 * self.force, 0.2 * self.force, 0]
-      animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-      animation.duration = CFTimeInterval(self.duration)
-      animation.isAdditive = true
-      animation.repeatCount = Float(repeatCount)
-      animation.beginTime = CACurrentMediaTime() + CFTimeInterval(self.delay)
-      self.layer.add(animation, forKey: "pop")
-    }, completion: completion)
-  }
-  
-  public func morph(repeatCount: Int, completion: AnimatableCompletion? = nil) {
-    CALayer.animate({
-      let morphX = CAKeyframeAnimation(keyPath: "transform.scale.x")
-      morphX.values = [1, 1.3 * self.force, 0.7, 1.3 * self.force, 1]
-      morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      morphX.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-     
-      let morphY = CAKeyframeAnimation(keyPath: "transform.scale.y")
-      morphY.values = [1, 0.7, 1.3 * self.force, 0.7, 1]
-      morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      morphY.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-      
-      let animationGroup = CAAnimationGroup()
-      animationGroup.animations = [morphX, morphY]
-      animationGroup.duration = CFTimeInterval(self.duration)
-      animationGroup.repeatCount = Float(repeatCount)
-      animationGroup.beginTime = CACurrentMediaTime() + CFTimeInterval(self.delay)
-      self.layer.add(animationGroup, forKey: "morph")
-    }, completion: completion)
-  }
-
-  public func squeeze(repeatCount: Int, completion: AnimatableCompletion? = nil) {
-    CALayer.animate({
-      let squeezeX = CAKeyframeAnimation(keyPath: "transform.scale.x")
-      squeezeX.values = [1, 1.5 * self.force, 0.5, 1.5 * self.force, 1]
-      squeezeX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      squeezeX.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-      
-      let squeezeY = CAKeyframeAnimation(keyPath: "transform.scale.y")
-      squeezeY.values = [1, 0.5, 1, 0.5, 1]
-      squeezeY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      squeezeY.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-      
-      let animationGroup = CAAnimationGroup()
-      animationGroup.animations = [squeezeX, squeezeY]
-      animationGroup.duration = CFTimeInterval(self.duration)
-      animationGroup.repeatCount = Float(repeatCount)
-      animationGroup.beginTime = CACurrentMediaTime() + CFTimeInterval(self.delay)
-      self.layer.add(animationGroup, forKey: "squeeze")
-    }, completion: completion)
-  }
-  
-  public func flash(repeatCount: Int, completion: AnimatableCompletion? = nil) {
-    CALayer.animate({
-      let animation = CABasicAnimation(keyPath: "opacity")
-      animation.fromValue = 1
-      animation.toValue = 0
-      animation.duration = CFTimeInterval(self.duration)
-      animation.repeatCount = Float(repeatCount) * 2.0
-      animation.autoreverses = true
-      animation.beginTime = CACurrentMediaTime() + CFTimeInterval(self.delay)
-      self.layer.add(animation, forKey: "flash")
-    }, completion: completion)
-  }
-  
-  public func wobble(repeatCount: Int, completion: AnimatableCompletion? = nil) {
-    CALayer.animate({
-      let rotation = CAKeyframeAnimation(keyPath: "transform.rotation")
-      rotation.values = [0, 0.3 * self.force, -0.3 * self.force, 0.3 * self.force, 0]
-      rotation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      rotation.isAdditive = true
-      
-      let positionX = CAKeyframeAnimation(keyPath: "position.x")
-      positionX.values = [0, 30 * self.force, -30 * self.force, 30 * self.force, 0]
-      positionX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      positionX.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-      positionX.isAdditive = true
-      
-      let animationGroup = CAAnimationGroup()
-      animationGroup.animations = [rotation, positionX]
-      animationGroup.duration = CFTimeInterval(self.duration)
-      animationGroup.beginTime = CACurrentMediaTime() + CFTimeInterval(self.delay)
-      animationGroup.repeatCount = Float(repeatCount)
-      self.layer.add(animationGroup, forKey: "wobble")
-    }, completion: completion)
-  }
-  
-  public func swing(repeatCount: Int, completion: AnimatableCompletion? = nil) {
-    CALayer.animate({
-      let animation = CAKeyframeAnimation(keyPath: "transform.rotation")
-      animation.values = [0, 0.3 * self.force, -0.3 * self.force, 0.3 * self.force, 0]
-      animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1]
-      animation.duration = CFTimeInterval(self.duration)
-      animation.isAdditive = true
-      animation.repeatCount = Float(repeatCount)
-      animation.beginTime = CACurrentMediaTime() + CFTimeInterval(self.delay)
-      self.layer.add(animation, forKey: "swing")
-    }, completion: completion)
-  }
-
-  public func moveBy(x: Double, y: Double, completion: AnimatableCompletion? = nil) {
-    if x.isNaN && y.isNaN {
-      return
-    }
-    
-    let xOffsetToMove = x.isNaN ? 0: CGFloat(x)
-    let yOffsetToMove = y.isNaN ? 0: CGFloat(y)
-    animateBy(x: xOffsetToMove, y: yOffsetToMove, completion: completion)
-  }
-  
-  // MARK: - Private
-  fileprivate func fadeOutIn(completion: AnimatableCompletion? = nil) {
+  }
+  
+  func fadeOutIn(completion: AnimatableCompletion? = nil) {
     CALayer.animate({
       let animation = CABasicAnimation(keyPath: "opacity")
       animation.fromValue = 1

      }
    )
  }
 
  
  fileprivate func animateIn(_ x: CGFloat, _ y: CGFloat, _ scaleX: CGFloat, _ scaleY: CGFloat, _ alpha: CGFloat, _ completion: AnimatableCompletion? = nil) {
    let translate = CGAffineTransform(translationX: x, y: y)
    let scale = CGAffineTransform(scaleX: scaleX, y: scaleY)
    let translateAndScale = translate.concatenating(scale)
    transform = translateAndScale

    UIView.animate(withDuration: duration, delay: delay, usingSpringWithDamping: damping, initialSpringVelocity: velocity, options: [],
      animations: {
        self.transform = CGAffineTransform.identity

      animation.isRemovedOnCompletion = false
      self.layer.add(animation, forKey: "fade")
      },
      completion: {
        self.alpha = 0
        completion?()
      }
    )
  }
  
  func animateBy(x: CGFloat, y: CGFloat, completion: AnimatableCompletion? = nil) {
    let translate = CGAffineTransform(translationX: x, y: y)
    UIView.animate(withDuration: duration, delay: delay, usingSpringWithDamping: damping, initialSpringVelocity: velocity, options: [],
      animations: {
