/**
 * Copyright 2013 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and

 * limitations under the License.
 */
 
/*
 * twine(), where |timing| is a web-animations timing dictionary with extra
 * properties that allow the custom control/ease of arbitrary js objects or dom
 * elements via the web animations API.
 *
 *   context: arbitrary |js-object| or |dom-element| [optional]
 *   timing.onstart: callback |function| when the animation starts [optional]
 *   timing.oniteration: callback |function| on animation iteration [optional]
 *   timing.onend: callback |function| when animation completes [optional]
 *   timing.delay: initial animation delay |float| in seconds [optional]
 *   timing.to: target |object| of context properties to animate [optional]
 *   timing.easing: |string| easing name [optional]
 *   timing.onupdate: callback |function| on animation updates [optional]
 *   duration: animation duration |float| in seconds [optional]
 *
 *  Return a web-animation object with a start() method to start it playing
 *  on the document timeline.
 */

twine = function(context, timing, duration) {
  (timing = timing || {});
  timing.duration = duration || "auto";
  if (timing.easing)
    timing.timingFunction = timing.easing;
  if (timing.delay)
    timing.startDelay = timing.delay;

  var anim = new Animation(null, onsample, timing);

  anim._valuesEnd = {};
  for (var property in timing.to)
    if (context && context[property] !== null && timing.to[property] !== null)
      anim._valuesEnd[property] = timing.to[property];

  anim.start = function() {
    anim._valuesStart = {}, anim._valuesDelta = {};
    for (var property in anim._valuesEnd) {
      anim._valuesStart[property] = context[property];
      anim._valuesDelta[property] = anim._valuesEnd[property] - context[property];
    }; 
    var player =  document.timeline.play(anim);
    return player, anim;
  };

  function onsample(fraction) {
    function customize(fraction) { return { ease: fraction } };
    if (typeof timing.onupdate === 'function')
      fraction = customize(timing.onupdate(fraction, 0, context)).ease || fraction;
    for (property in anim._valuesDelta)
      context[property] = anim._valuesStart[property] + anim._valuesDelta[property] * fraction;
  }

  anim.stop = function() {
    return anim.player && (anim.player.paused = true), anim;
  };

  return anim;
};

@@ -2317,10 +2317,8 @@
    %7D
-; 
 %0A   
@@ -2362,16 +2362,115 @@
 (anim);%0A
+    if (typeof timing.onend === 'function')%0A      player.addEventListener('finish', timing.onend);%0A
     retu

Fix globe demo