<commit_before>﻿import definition = require("ui/animation");
import common = require("./animation-common");
import viewModule = require("ui/core/view");
import trace = require("trace");
import enums = require("ui/enums");

global.moduleMerge(common, exports);

var _transform = "_transform";
var _skip = "_skip";

var FLT_MAX = 340282346638528859811704183484516925440.000000;

declare var CASpringAnimation:any;

class AnimationDelegateImpl extends NSObject {

    public nextAnimation: Function;

    private _finishedCallback: Function;
    private _propertyAnimation: common.PropertyAnimation;

    public static initWithFinishedCallback(finishedCallback: Function, propertyAnimation: common.PropertyAnimation): AnimationDelegateImpl {
        let delegate = <AnimationDelegateImpl>AnimationDelegateImpl.new();
        delegate._finishedCallback = finishedCallback;
        delegate._propertyAnimation = propertyAnimation;
        return delegate;
    }

    animationDidStart(anim: CAAnimation): void {
       var nativeView = <UIView>this._propertyAnimation.target._nativeView;
       var propertyNameToAnimate = this._propertyAnimation.property;
       var value = this._propertyAnimation.value;

       (<any>this._propertyAnimation.target)._suspendPresentationLayerUpdates();

       switch (this._propertyAnimation.property) {
           case common.Properties.backgroundColor:
               this._propertyAnimation.target.backgroundColor = value;
               break;
           case common.Properties.opacity:
               this._propertyAnimation.target.opacity = value;
               break;
           case common.Properties.rotate:
               this._propertyAnimation.target.rotate = value;
               break;
           case _transform:
               if (value[common.Properties.translate] !== undefined) {
                  this._propertyAnimation.target.translateX = value[common.Properties.translate].x;
                  this._propertyAnimation.target.translateY = value[common.Properties.translate].y;
               }
               if (value[common.Properties.scale] !== undefined) {
                  this._propertyAnimation.target.scaleX = value[common.Properties.scale].x;
                  this._propertyAnimation.target.scaleY = value[common.Properties.scale].y;
               }
               break;
        }

        (<any>this._propertyAnimation.target)._resumePresentationLayerUpdates();

   }

    public animationDidStopFinished(anim: CAAnimation, flag: boolean): void {
        if (this._finishedCallback) {
            var cancelled = !flag;
            // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values.
            this._finishedCallback(cancelled);
        }
        if (!flag) {
            if ((<any>this._propertyAnimation)._propertyResetCallback) {
               (<any>this._propertyAnimation)._propertyResetCallback((<any>this._propertyAnimation)._originalValue);
            }
        }
        if (flag && this.nextAnimation) {
            this.nextAnimation();
        }
    }

    public uiview_animationWillStart(animationID: string, context: any): void {
        trace.write("AnimationDelegateImpl.animationWillStart, animationID: " + animationID, trace.categories.Animation);
    }

    public uiview_animationDidStop(animationID: string, finished: boolean, context: any): void {
        trace.write("AnimationDelegateImpl.animationDidStop, animationID: " + animationID + ", finished: " + finished, trace.categories.Animation);
        if (this._finishedCallback) {
            var cancelled = !finished;
            // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values.
            this._finishedCallback(cancelled);
        }
        if (!finished) {
            if ((<any>this._propertyAnimation)._propertyResetCallback) {
               (<any>this._propertyAnimation)._propertyResetCallback((<any>this._propertyAnimation)._originalValue);
            }
        }
        if (finished && this.nextAnimation) {
            this.nextAnimation();
        }
    }
}

export class Animation extends common.Animation implements definition.Animation {
    private _iOSAnimationFunction: Function;
    private _finishedAnimations: number;
    private _cancelledAnimations: number;
    private _mergedPropertyAnimations: Array<common.PropertyAnimation>;

    public play(): Promise<void> {
        var animationFinishedPromise = super.play();

        this._finishedAnimations = 0;
        this._cancelledAnimations = 0;

        this._iOSAnimationFunction();
        return animationFinishedPromise;
    }

    public cancel(): void {
        super.cancel();

        var i = 0;
        var length = this._mergedPropertyAnimations.length;
        for (; i < length; i++) {
            (<UIView>this._mergedPropertyAnimations[i].target._nativeView).layer.removeAllAnimations();
        }
    }

    constructor(animationDefinitions: Array<definition.AnimationDefinition>, playSequentially?: boolean) {
        super(animationDefinitions, playSequentially);

        trace.write("Non-merged Property Animations: " + this._propertyAnimations.length, trace.categories.Animation);
        this._mergedPropertyAnimations = Animation._mergeAffineTransformAnimations(this._propertyAnimations);
        trace.write("Merged Property Animations: " + this._mergedPropertyAnimations.length, trace.categories.Animation);

        var that = this;
        var animationFinishedCallback = (cancelled: boolean) => {
            if (that._playSequentially) {
                // This function will be called by the last animation when done or by another animation if the user cancels them halfway through.
                if (cancelled) {
                    that._rejectAnimationFinishedPromise();
                }
                else {
                    that._resolveAnimationFinishedPromise();
                }
            }
            else {
                // This callback will be called by each INDIVIDUAL animation when it finishes or is cancelled.
                if (cancelled) {
                    that._cancelledAnimations++;
                }
                else {
                    that._finishedAnimations++;
                }

                if (that._cancelledAnimations > 0 && (that._cancelledAnimations + that._finishedAnimations) === that._mergedPropertyAnimations.length) {
                    trace.write(that._cancelledAnimations + " animations cancelled.", trace.categories.Animation);
                    that._rejectAnimationFinishedPromise();
                }
                else if (that._finishedAnimations === that._mergedPropertyAnimations.length) {
                    trace.write(that._finishedAnimations + " animations finished.", trace.categories.Animation);
                    that._resolveAnimationFinishedPromise();
                }
            }
        };

        this._iOSAnimationFunction = Animation._createiOSAnimationFunction(this._mergedPropertyAnimations, 0, this._playSequentially, animationFinishedCallback, this);
    }

    private static _createiOSAnimationFunction(propertyAnimations: Array<common.PropertyAnimation>, index: number, playSequentially: boolean, finishedCallback: (cancelled?: boolean) => void, that:Animation): Function {
        return (cancelled?: boolean) => {
            if (cancelled && finishedCallback) {
                trace.write("Animation " + (index - 1).toString() + " was cancelled. Will skip the rest of animations and call finishedCallback(true).", trace.categories.Animation);
                finishedCallback(cancelled);
                return;
            }

           var animation = propertyAnimations[index];
           var nativeView = <UIView>animation.target._nativeView;
           var propertyNameToAnimate = animation.property;
           var value = animation.value;
           var originalValue;
           var presentationLayer = nativeView.layer.presentationLayer();
           var tempRotate = animation.target.rotate * Math.PI / 180;
           var abs

           switch (animation.property) {
               case common.Properties.backgroundColor:
                   (<any>animation)._originalValue = animation.target.backgroundColor;
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.backgroundColor = value };
                   if (presentationLayer != null) {
                     if (nativeView instanceof UILabel) {
                        nativeView.backgroundColor = UIColor.clearColor();
                     }
                     originalValue = presentationLayer.backgroundColor;
                   }
                   else {
                     originalValue = nativeView.layer.backgroundColor;
                   }
                   if (nativeView instanceof UILabel) {
                       originalValue = nativeView.layer.backgroundColor;
                       nativeView.setValueForKey(UIColor.clearColor(), "backgroundColor");
                   }
                   value = value.CGColor;
                   break;
               case common.Properties.opacity:
                   (<any>animation)._originalValue = animation.target.opacity;
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.opacity = value };
                   if (presentationLayer != null) {
                     originalValue = presentationLayer.opacity;
                   }
                   else {
                     originalValue = nativeView.layer.opacity;
                   }
                   break;
               case common.Properties.rotate:
                   (<any>animation)._originalValue = animation.target.rotate;
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.rotate = value };
                   propertyNameToAnimate = "transform.rotation";
                   if (presentationLayer != null) {
                     originalValue = presentationLayer.valueForKeyPath("transform.rotation");
                   }
                   else {
                     originalValue = nativeView.layer.valueForKeyPath("transform.rotation");
                   }
                   value = value * Math.PI / 180;
                   abs = fabs(originalValue - value);
                   if (abs < 0.001 && originalValue !== tempRotate) {
                       originalValue = tempRotate;
                   }
                   break;
               case common.Properties.translate:
                   (<any>animation)._originalValue = { x:animation.target.translateX, y:animation.target.translateY };
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.translateX = value.x; animation.target.translateY = value.y; };
                   propertyNameToAnimate = "transform"
                   if (presentationLayer != null) {
                     originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
                   }
                   else {
                     originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
                   }
                   value = NSValue.valueWithCATransform3D(CATransform3DTranslate(nativeView.layer.transform, value.x, value.y, 0));
                   break;
               case common.Properties.scale:
                   (<any>animation)._originalValue = { x:animation.target.scaleX, y:animation.target.scaleY };
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.scaleX = value.x; animation.target.scaleY = value.y; };
                   propertyNameToAnimate = "transform"
                   if (presentationLayer != null) {
                     originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
                   }
                   else {
                     originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
                   }
                   value = NSValue.valueWithCATransform3D(CATransform3DScale(nativeView.layer.transform, value.x, value.y, 1));
                   break;
               case _transform:
                   if (presentationLayer != null) {
                     originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
                   }
                   else {
                     originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
                   }
                   (<any>animation)._originalValue = { xs:animation.target.scaleX, ys:animation.target.scaleY,
                                                       xt:animation.target.translateX, yt:animation.target.translateY };
                   (<any>animation)._propertyResetCallback = (value) => {
                        animation.target.translateX = value.xt;
                        animation.target.translateY = value.yt;
                        animation.target.scaleX = value.xs;
                        animation.target.scaleY = value.ys;
                   };
                   propertyNameToAnimate = "transform"
                   value = NSValue.valueWithCATransform3D(Animation._createNativeAffineTransform(animation));
                   break;
               default:
                   throw new Error("Cannot animate " + animation.property);
           }

           var nativeAnimation;
           var isSpring = false;

           if (animation.curve === enums.AnimationCurve.spring) {

              // nativeAnimation = CASpringAnimation.animationWithKeyPath(propertyNameToAnimate);
              // nativeAnimation.duration = nativeAnimation.settlingDuration;
              // nativeAnimation.damping = 3;

              var duration = 0.3;
              if (animation.duration !== undefined) {
                  duration = animation.duration / 1000.0;
              }
              var delay = 0;
              if (animation.delay !== undefined) {
                  delay = CACurrentMediaTime() + (animation.delay / 1000.0);
              }

              var animationDelegate: AnimationDelegateImpl;
              animationDelegate = AnimationDelegateImpl.initWithFinishedCallback(finishedCallback, animation);

              var callback = undefined;
              if (index+1 < propertyAnimations.length) {
                 callback = Animation._createiOSAnimationFunction(propertyAnimations, index+1, playSequentially, finishedCallback, that);
                 if (!playSequentially) {
                      callback();
                 }
                 else {
                     animationDelegate.nextAnimation = callback;
                 }
               }

              UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(duration, delay, 0.2, 0,
                UIViewKeyframeAnimationOptions.UIViewKeyframeAnimationOptionCalculationModeLinear,
                () => {

                  if (animationDelegate) {
                     UIView.setAnimationDelegate(animationDelegate);
                     UIView.setAnimationWillStartSelector("uiview_animationWillStart");
                     UIView.setAnimationDidStopSelector("uiview_animationDidStop");
                 }

                  if (animation.iterations !== undefined) {
                      if (animation.iterations === Number.POSITIVE_INFINITY) {
                          UIView.setAnimationRepeatCount(FLT_MAX);
                      }
                      else {
                          UIView.setAnimationRepeatCount(animation.iterations - 1);
                      }
                  }

                  switch (animation.property) {
                      case common.Properties.backgroundColor:
                          animation.target.backgroundColor = value;
                          break;
                      case common.Properties.opacity:
                          animation.target.opacity = value;
                          break;
                      case common.Properties.rotate:
                          nativeView.layer.setValueForKey(value, propertyNameToAnimate);
                          break;
                      case _transform:
                          nativeView.layer.setValueForKey(value, propertyNameToAnimate);
                          break;
                   }

                }, function (finished:boolean) {
                    if (finished) {
                      if (animation.property === _transform) {
                        if (animation.value[common.Properties.translate] !== undefined) {
                            animation.target.translateX = animation.value[common.Properties.translate].x;
                            animation.target.translateY = animation.value[common.Properties.translate].y;
                        }
                        if (animation.value[common.Properties.scale] !== undefined) {
                            animation.target.scaleX = animation.value[common.Properties.scale].x;
                            animation.target.scaleY = animation.value[common.Properties.scale].y;
                        }
                      }
                    }
                });

              return;
           }
           else {
              nativeAnimation = CABasicAnimation.animationWithKeyPath(propertyNameToAnimate);
           }
           nativeAnimation.fromValue = originalValue;
           nativeAnimation.toValue = value;
           if (animation.duration !== undefined) {
               nativeAnimation.duration = animation.duration / 1000.0;
           }
           else {
               nativeAnimation.duration = 0.3;
           }
           if (animation.delay !== undefined) {
               nativeAnimation.beginTime = CACurrentMediaTime() + (animation.delay / 1000.0);
           }
<commit_msg>Fixed: animation chaining is not working when using spring animation<commit_after>﻿import definition = require("ui/animation");
import common = require("./animation-common");
import viewModule = require("ui/core/view");
import trace = require("trace");
import enums = require("ui/enums");

global.moduleMerge(common, exports);

var _transform = "_transform";
var _skip = "_skip";

var FLT_MAX = 340282346638528859811704183484516925440.000000;

declare var CASpringAnimation:any;

class AnimationDelegateImpl extends NSObject {

    public nextAnimation: Function;

    private _finishedCallback: Function;
    private _propertyAnimation: common.PropertyAnimation;

    public static initWithFinishedCallback(finishedCallback: Function, propertyAnimation: common.PropertyAnimation): AnimationDelegateImpl {
        let delegate = <AnimationDelegateImpl>AnimationDelegateImpl.new();
        delegate._finishedCallback = finishedCallback;
        delegate._propertyAnimation = propertyAnimation;
        return delegate;
    }

    animationDidStart(anim: CAAnimation): void {
       var nativeView = <UIView>this._propertyAnimation.target._nativeView;
       var propertyNameToAnimate = this._propertyAnimation.property;
       var value = this._propertyAnimation.value;

       (<any>this._propertyAnimation.target)._suspendPresentationLayerUpdates();

       switch (this._propertyAnimation.property) {
           case common.Properties.backgroundColor:
               this._propertyAnimation.target.backgroundColor = value;
               break;
           case common.Properties.opacity:
               this._propertyAnimation.target.opacity = value;
               break;
           case common.Properties.rotate:
               this._propertyAnimation.target.rotate = value;
               break;
           case _transform:
               if (value[common.Properties.translate] !== undefined) {
                  this._propertyAnimation.target.translateX = value[common.Properties.translate].x;
                  this._propertyAnimation.target.translateY = value[common.Properties.translate].y;
               }
               if (value[common.Properties.scale] !== undefined) {
                  this._propertyAnimation.target.scaleX = value[common.Properties.scale].x;
                  this._propertyAnimation.target.scaleY = value[common.Properties.scale].y;
               }
               break;
        }

        (<any>this._propertyAnimation.target)._resumePresentationLayerUpdates();
   }

    public animationDidStopFinished(anim: CAAnimation, flag: boolean): void {
        if (this._finishedCallback) {
            var cancelled = !flag;
            // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values.
            this._finishedCallback(cancelled);
        }
        if (!flag) {
            if ((<any>this._propertyAnimation)._propertyResetCallback) {
               (<any>this._propertyAnimation)._propertyResetCallback((<any>this._propertyAnimation)._originalValue);
            }
        }
        if (flag && this.nextAnimation) {
            this.nextAnimation();
        }
    }

    // public uiview_animationWillStart(animationID: string, context: any): void {
    //     trace.write("AnimationDelegateImpl.animationWillStart, animationID: " + animationID, trace.categories.Animation);
    // }
    //
    // public uiview_animationDidStop(animationID: string, finished: boolean, context: any): void {
    //     trace.write("AnimationDelegateImpl.animationDidStop, animationID: " + animationID + ", finished: " + finished, trace.categories.Animation);
    //     if (this._finishedCallback) {
    //         var cancelled = !finished;
    //         // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values.
    //         this._finishedCallback(cancelled);
    //     }
    //     if (!finished) {
    //         if ((<any>this._propertyAnimation)._propertyResetCallback) {
    //            (<any>this._propertyAnimation)._propertyResetCallback((<any>this._propertyAnimation)._originalValue);
    //         }
    //     }
    //     if (finished && this.nextAnimation) {
    //         this.nextAnimation();
    //     }
    // }
}

export class Animation extends common.Animation implements definition.Animation {
    private _iOSAnimationFunction: Function;
    private _finishedAnimations: number;
    private _cancelledAnimations: number;
    private _mergedPropertyAnimations: Array<common.PropertyAnimation>;

    public play(): Promise<void> {
        var animationFinishedPromise = super.play();

        this._finishedAnimations = 0;
        this._cancelledAnimations = 0;

        this._iOSAnimationFunction();
        return animationFinishedPromise;
    }

    public cancel(): void {
        super.cancel();

        var i = 0;
        var length = this._mergedPropertyAnimations.length;
        for (; i < length; i++) {
            (<UIView>this._mergedPropertyAnimations[i].target._nativeView).layer.removeAllAnimations();
        }
    }

    constructor(animationDefinitions: Array<definition.AnimationDefinition>, playSequentially?: boolean) {
        super(animationDefinitions, playSequentially);

        trace.write("Non-merged Property Animations: " + this._propertyAnimations.length, trace.categories.Animation);
        this._mergedPropertyAnimations = Animation._mergeAffineTransformAnimations(this._propertyAnimations);
        trace.write("Merged Property Animations: " + this._mergedPropertyAnimations.length, trace.categories.Animation);

        var that = this;
        var animationFinishedCallback = (cancelled: boolean) => {
            if (that._playSequentially) {
                // This function will be called by the last animation when done or by another animation if the user cancels them halfway through.
                if (cancelled) {
                    that._rejectAnimationFinishedPromise();
                }
                else {
                    that._resolveAnimationFinishedPromise();
                }
            }
            else {
                // This callback will be called by each INDIVIDUAL animation when it finishes or is cancelled.
                if (cancelled) {
                    that._cancelledAnimations++;
                }
                else {
                    that._finishedAnimations++;
                }

                if (that._cancelledAnimations > 0 && (that._cancelledAnimations + that._finishedAnimations) === that._mergedPropertyAnimations.length) {
                    trace.write(that._cancelledAnimations + " animations cancelled.", trace.categories.Animation);
                    that._rejectAnimationFinishedPromise();
                }
                else if (that._finishedAnimations === that._mergedPropertyAnimations.length) {
                    trace.write(that._finishedAnimations + " animations finished.", trace.categories.Animation);
                    that._resolveAnimationFinishedPromise();
                }
            }
        };

        this._iOSAnimationFunction = Animation._createiOSAnimationFunction(this._mergedPropertyAnimations, 0, this._playSequentially, animationFinishedCallback, this);
    }

    private static _createiOSAnimationFunction(propertyAnimations: Array<common.PropertyAnimation>, index: number, playSequentially: boolean, finishedCallback: (cancelled?: boolean) => void, that:Animation): Function {
        return (cancelled?: boolean) => {
            if (cancelled && finishedCallback) {
                trace.write("Animation " + (index - 1).toString() + " was cancelled. Will skip the rest of animations and call finishedCallback(true).", trace.categories.Animation);
                finishedCallback(cancelled);
                return;
            }

           var animation = propertyAnimations[index];
           var nativeView = <UIView>animation.target._nativeView;
           var propertyNameToAnimate = animation.property;
           var value = animation.value;
           var originalValue;
           var presentationLayer = nativeView.layer.presentationLayer();
           var tempRotate = animation.target.rotate * Math.PI / 180;
           var abs

           switch (animation.property) {
               case common.Properties.backgroundColor:
                   (<any>animation)._originalValue = animation.target.backgroundColor;
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.backgroundColor = value };
                   if (presentationLayer != null) {
                     if (nativeView instanceof UILabel) {
                        nativeView.backgroundColor = UIColor.clearColor();
                     }
                     originalValue = presentationLayer.backgroundColor;
                   }
                   else {
                     originalValue = nativeView.layer.backgroundColor;
                   }
                   if (nativeView instanceof UILabel) {
                       originalValue = nativeView.layer.backgroundColor;
                       nativeView.setValueForKey(UIColor.clearColor(), "backgroundColor");
                   }
                   value = value.CGColor;
                   break;
               case common.Properties.opacity:
                   (<any>animation)._originalValue = animation.target.opacity;
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.opacity = value };
                   if (presentationLayer != null) {
                     originalValue = presentationLayer.opacity;
                   }
                   else {
                     originalValue = nativeView.layer.opacity;
                   }
                   break;
               case common.Properties.rotate:
                   (<any>animation)._originalValue = animation.target.rotate;
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.rotate = value };
                   propertyNameToAnimate = "transform.rotation";
                   if (presentationLayer != null) {
                     originalValue = presentationLayer.valueForKeyPath("transform.rotation");
                   }
                   else {
                     originalValue = nativeView.layer.valueForKeyPath("transform.rotation");
                   }
                   value = value * Math.PI / 180;
                   abs = fabs(originalValue - value);
                   if (abs < 0.001 && originalValue !== tempRotate) {
                       originalValue = tempRotate;
                   }
                   break;
               case common.Properties.translate:
                   (<any>animation)._originalValue = { x:animation.target.translateX, y:animation.target.translateY };
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.translateX = value.x; animation.target.translateY = value.y; };
                   propertyNameToAnimate = "transform"
                   if (presentationLayer != null) {
                     originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
                   }
                   else {
                     originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
                   }
                   value = NSValue.valueWithCATransform3D(CATransform3DTranslate(nativeView.layer.transform, value.x, value.y, 0));
                   break;
               case common.Properties.scale:
                   (<any>animation)._originalValue = { x:animation.target.scaleX, y:animation.target.scaleY };
                   (<any>animation)._propertyResetCallback = (value) => { animation.target.scaleX = value.x; animation.target.scaleY = value.y; };
                   propertyNameToAnimate = "transform"
                   if (presentationLayer != null) {
                     originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
                   }
                   else {
                     originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
                   }
                   value = NSValue.valueWithCATransform3D(CATransform3DScale(nativeView.layer.transform, value.x, value.y, 1));
                   break;
               case _transform:
                   if (presentationLayer != null) {
                     originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
                   }
                   else {
                     originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
                   }
                   (<any>animation)._originalValue = { xs:animation.target.scaleX, ys:animation.target.scaleY,
                                                       xt:animation.target.translateX, yt:animation.target.translateY };
                   (<any>animation)._propertyResetCallback = (value) => {
                        animation.target.translateX = value.xt;
                        animation.target.translateY = value.yt;
                        animation.target.scaleX = value.xs;
                        animation.target.scaleY = value.ys;
                   };
                   propertyNameToAnimate = "transform"
                   value = NSValue.valueWithCATransform3D(Animation._createNativeAffineTransform(animation));
                   break;
               default:
                   throw new Error("Cannot animate " + animation.property);
           }

           var nativeAnimation;
           var isSpring = false;

           if (animation.curve === enums.AnimationCurve.spring) {

              // nativeAnimation = CASpringAnimation.animationWithKeyPath(propertyNameToAnimate);
              // nativeAnimation.duration = nativeAnimation.settlingDuration;
              // nativeAnimation.damping = 3;

              var duration = 0.3;
              if (animation.duration !== undefined) {
                  duration = animation.duration / 1000.0;
              }
              var delay = 0;
              if (animation.delay !== undefined) {
                  delay = CACurrentMediaTime() + (animation.delay / 1000.0);
              }

              var callback = undefined;
              var nextAnimation;
              if (index + 1 < propertyAnimations.length) {
                  callback = Animation._createiOSAnimationFunction(propertyAnimations, index + 1, playSequentially, finishedCallback, that);
                  if (!playSequentially) {
                      callback();
                  }
                  else {
                      nextAnimation = callback;
                  }
              }

              UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(duration, delay, 0.2, 0,
                UIViewKeyframeAnimationOptions.UIViewKeyframeAnimationOptionCalculationModeLinear,
                () => {
                  if (animation.iterations !== undefined) {
                      if (animation.iterations === Number.POSITIVE_INFINITY) {
                          UIView.setAnimationRepeatCount(FLT_MAX);
                      }
                      else {
                          UIView.setAnimationRepeatCount(animation.iterations - 1);
                      }
                  }

                  switch (animation.property) {
                      case common.Properties.backgroundColor:
                          animation.target.backgroundColor = value;
                          break;
                      case common.Properties.opacity:
                          animation.target.opacity = value;
                          break;
                      case common.Properties.rotate:
                          nativeView.layer.setValueForKey(value, propertyNameToAnimate);
                          break;
                      case _transform:
                          (<any>animation)._originalValue = nativeView.layer.transform;
                          nativeView.layer.setValueForKey(value, propertyNameToAnimate);
                          (<any>animation)._propertyResetCallback = function (value) {
                             nativeView.layer.transform = value;
                          }
                          break;
                   }

                }, function (finished:boolean) {
                    if (finished) {
                      if (animation.property === _transform) {
                        if (animation.value[common.Properties.translate] !== undefined) {
                            animation.target.translateX = animation.value[common.Properties.translate].x;
                            animation.target.translateY = animation.value[common.Properties.translate].y;
                        }
                        if (animation.value[common.Properties.scale] !== undefined) {
                            animation.target.scaleX = animation.value[common.Properties.scale].x;
                            animation.target.scaleY = animation.value[common.Properties.scale].y;
                        }
                      }
                    }
                    else {
                        if ((<any>animation)._propertyResetCallback) {
                            (<any>animation)._propertyResetCallback((<any>animation)._originalValue);
                        }
                    }
                    if (finishedCallback) {
                        var cancelled = !finished;
                        finishedCallback(cancelled);
                    }
                    if (finished && nextAnimation) {
                        nextAnimation();
                    }
                });

              return;
           }
           else {
              nativeAnimation = CABasicAnimation.animationWithKeyPath(propertyNameToAnimate);
           }
           nativeAnimation.fromValue = originalValue;
           nativeAnimation.toValue = value;
           if (animation.duration !== undefined) {
               nativeAnimation.duration = animation.duration / 1000.0;
           }
           else {
               nativeAnimation.duration = 0.3;
           }
           if (animation.delay !== undefined) {
               nativeAnimation.beginTime = CACurrentMediaTime() + (animation.delay / 1000.0);
           }

{'fraction_non_alphanumeric': 0.08746635909265667, 'fraction_numerical': 0.005821936617784369, 'mean_word_length': 1.7787104158718046, 'pattern_counts': {'":': 0, '<': 70, '<?xml version=': 0, '>': 86, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3841750', 'n_tokens_mistral': 8611, 'n_tokens_neox': 7932, 'n_words': 1475}