Merge "Add some free zoom to lockHardwareCanvas" into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 241948c..074175b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3052,9 +3052,10 @@
     method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
   }
 
-  public class StateListAnimator {
+  public class StateListAnimator implements java.lang.Cloneable {
     ctor public StateListAnimator();
     method public void addState(int[], android.animation.Animator);
+    method public android.animation.StateListAnimator clone();
     method public void jumpToCurrentState();
   }
 
@@ -17034,6 +17035,7 @@
   }
 
   public class Network implements android.os.Parcelable {
+    method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
     method public void bindSocket(java.net.Socket) throws java.io.IOException;
     method public int describeContents();
     method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
@@ -28711,6 +28713,7 @@
     method public void updateMmsSendStatus(android.content.Context, int, byte[], int, android.net.Uri);
     method public void updateSmsSendStatus(int, boolean);
     field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
+    field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
     field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
     field public static final java.lang.String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars";
     field public static final java.lang.String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars";
@@ -28820,6 +28823,9 @@
     ctor public SubInfoRecord();
     ctor public SubInfoRecord(long, java.lang.String, int, java.lang.String, int, int, java.lang.String, int, int, int[], int, int);
     method public int describeContents();
+    method public int getColor();
+    method public android.graphics.drawable.BitmapDrawable getIconDrawable();
+    method public java.lang.String getLabel();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public int color;
@@ -34908,6 +34914,7 @@
     field public static final int FLAG_HARDWARE_ACCELERATED = 16777216; // 0x1000000
     field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000
     field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
+    field public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 1073741824; // 0x40000000
     field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
     field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
     field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
@@ -35422,13 +35429,13 @@
 
 package android.view.animation {
 
-  public class AccelerateDecelerateInterpolator implements android.view.animation.Interpolator {
+  public class AccelerateDecelerateInterpolator extends android.view.animation.BaseInterpolator {
     ctor public AccelerateDecelerateInterpolator();
     ctor public AccelerateDecelerateInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class AccelerateInterpolator implements android.view.animation.Interpolator {
+  public class AccelerateInterpolator extends android.view.animation.BaseInterpolator {
     ctor public AccelerateInterpolator();
     ctor public AccelerateInterpolator(float);
     ctor public AccelerateInterpolator(android.content.Context, android.util.AttributeSet);
@@ -35530,14 +35537,14 @@
     method public static android.view.animation.Animation makeOutAnimation(android.content.Context, boolean);
   }
 
-  public class AnticipateInterpolator implements android.view.animation.Interpolator {
+  public class AnticipateInterpolator extends android.view.animation.BaseInterpolator {
     ctor public AnticipateInterpolator();
     ctor public AnticipateInterpolator(float);
     ctor public AnticipateInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class AnticipateOvershootInterpolator implements android.view.animation.Interpolator {
+  public class AnticipateOvershootInterpolator extends android.view.animation.BaseInterpolator {
     ctor public AnticipateOvershootInterpolator();
     ctor public AnticipateOvershootInterpolator(float);
     ctor public AnticipateOvershootInterpolator(float, float);
@@ -35545,19 +35552,23 @@
     method public float getInterpolation(float);
   }
 
-  public class BounceInterpolator implements android.view.animation.Interpolator {
+  public abstract class BaseInterpolator implements android.view.animation.Interpolator {
+    ctor public BaseInterpolator();
+  }
+
+  public class BounceInterpolator extends android.view.animation.BaseInterpolator {
     ctor public BounceInterpolator();
     ctor public BounceInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class CycleInterpolator implements android.view.animation.Interpolator {
+  public class CycleInterpolator extends android.view.animation.BaseInterpolator {
     ctor public CycleInterpolator(float);
     ctor public CycleInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class DecelerateInterpolator implements android.view.animation.Interpolator {
+  public class DecelerateInterpolator extends android.view.animation.BaseInterpolator {
     ctor public DecelerateInterpolator();
     ctor public DecelerateInterpolator(float);
     ctor public DecelerateInterpolator(android.content.Context, android.util.AttributeSet);
@@ -35632,20 +35643,20 @@
     field public int index;
   }
 
-  public class LinearInterpolator implements android.view.animation.Interpolator {
+  public class LinearInterpolator extends android.view.animation.BaseInterpolator {
     ctor public LinearInterpolator();
     ctor public LinearInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class OvershootInterpolator implements android.view.animation.Interpolator {
+  public class OvershootInterpolator extends android.view.animation.BaseInterpolator {
     ctor public OvershootInterpolator();
     ctor public OvershootInterpolator(float);
     ctor public OvershootInterpolator(android.content.Context, android.util.AttributeSet);
     method public float getInterpolation(float);
   }
 
-  public class PathInterpolator implements android.view.animation.Interpolator {
+  public class PathInterpolator extends android.view.animation.BaseInterpolator {
     ctor public PathInterpolator(android.graphics.Path);
     ctor public PathInterpolator(float, float);
     ctor public PathInterpolator(float, float, float, float);
@@ -38171,6 +38182,7 @@
     method public int getSoftInputMode();
     method public int getWidth();
     method public boolean isAboveAnchor();
+    method public boolean isAttachedInDecor();
     method public boolean isClippingEnabled();
     method public boolean isFocusable();
     method public boolean isOutsideTouchable();
@@ -38178,6 +38190,7 @@
     method public boolean isSplitTouchEnabled();
     method public boolean isTouchable();
     method public void setAnimationStyle(int);
+    method public void setAttachedInDecor(boolean);
     method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 3720c81..da48709 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -16,6 +16,8 @@
 
 package android.animation;
 
+import android.content.res.ConstantState;
+
 import java.util.ArrayList;
 
 /**
@@ -41,6 +43,18 @@
     boolean mPaused = false;
 
     /**
+     * A set of flags which identify the type of configuration changes that can affect this
+     * Animator. Used by the Animator cache.
+     */
+    int mChangingConfigurations = 0;
+
+    /**
+     * If this animator is inflated from a constant state, keep a reference to it so that
+     * ConstantState will not be garbage collected until this animator is collected
+     */
+    private AnimatorConstantState mConstantState;
+
+    /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
      * running after that delay elapses. A non-delayed animation will have its initial
      * value(s) set immediately, followed by calls to
@@ -295,25 +309,71 @@
         }
     }
 
+    /**
+     * Return a mask of the configuration parameters for which this animator may change, requiring
+     * that it should be re-created from Resources. The default implementation returns whatever
+     * value was provided through setChangingConfigurations(int) or 0 by default.
+     *
+     * @return Returns a mask of the changing configuration parameters, as defined by
+     * {@link android.content.pm.ActivityInfo}.
+     * @see android.content.pm.ActivityInfo
+     * @hide
+     */
+    public int getChangingConfigurations() {
+        return mChangingConfigurations;
+    }
+
+    /**
+     * Set a mask of the configuration parameters for which this animator may change, requiring
+     * that it be re-created from resource.
+     *
+     * @param configs A mask of the changing configuration parameters, as
+     * defined by {@link android.content.pm.ActivityInfo}.
+     *
+     * @see android.content.pm.ActivityInfo
+     * @hide
+     */
+    public void setChangingConfigurations(int configs) {
+        mChangingConfigurations = configs;
+    }
+
+    /**
+     * Sets the changing configurations value to the union of the current changing configurations
+     * and the provided configs.
+     * This method is called while loading the animator.
+     * @hide
+     */
+    public void appendChangingConfigurations(int configs) {
+        mChangingConfigurations |= configs;
+    }
+
+    /**
+     * Return a {@link android.content.res.ConstantState} instance that holds the shared state of
+     * this Animator.
+     * <p>
+     * This constant state is used to create new instances of this animator when needed, instead
+     * of re-loading it from resources. Default implementation creates a new
+     * {@link AnimatorConstantState}. You can override this method to provide your custom logic or
+     * return null if you don't want this animator to be cached.
+     *
+     * @return The ConfigurationBoundResourceCache.BaseConstantState associated to this Animator.
+     * @see android.content.res.ConstantState
+     * @see #clone()
+     * @hide
+     */
+    public ConstantState<Animator> createConstantState() {
+        return new AnimatorConstantState(this);
+    }
+
     @Override
     public Animator clone() {
         try {
             final Animator anim = (Animator) super.clone();
             if (mListeners != null) {
-                ArrayList<AnimatorListener> oldListeners = mListeners;
-                anim.mListeners = new ArrayList<AnimatorListener>();
-                int numListeners = oldListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    anim.mListeners.add(oldListeners.get(i));
-                }
+                anim.mListeners = new ArrayList<AnimatorListener>(mListeners);
             }
             if (mPauseListeners != null) {
-                ArrayList<AnimatorPauseListener> oldListeners = mPauseListeners;
-                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>();
-                int numListeners = oldListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    anim.mPauseListeners.add(oldListeners.get(i));
-                }
+                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners);
             }
             return anim;
         } catch (CloneNotSupportedException e) {
@@ -469,4 +529,35 @@
     public void setAllowRunningAsynchronously(boolean mayRunAsync) {
         // It is up to subclasses to support this, if they can.
     }
+
+    /**
+     * Creates a {@link ConstantState} which holds changing configurations information associated
+     * with the given Animator.
+     * <p>
+     * When {@link #newInstance()} is called, default implementation clones the Animator.
+     */
+    private static class AnimatorConstantState extends ConstantState<Animator> {
+
+        final Animator mAnimator;
+        int mChangingConf;
+
+        public AnimatorConstantState(Animator animator) {
+            mAnimator = animator;
+            // ensure a reference back to here so that constante state is not gc'ed.
+            mAnimator.mConstantState = this;
+            mChangingConf = mAnimator.getChangingConfigurations();
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConf;
+        }
+
+        @Override
+        public Animator newInstance() {
+            final Animator clone = mAnimator.clone();
+            clone.mConstantState = this;
+            return clone;
+        }
+    }
 }
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 25417ed..688d7e4 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -16,6 +16,8 @@
 package android.animation;
 
 import android.content.Context;
+import android.content.res.ConfigurationBoundResourceCache;
+import android.content.res.ConstantState;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.Resources.Theme;
@@ -30,6 +32,8 @@
 import android.util.Xml;
 import android.view.InflateException;
 import android.view.animation.AnimationUtils;
+import android.view.animation.BaseInterpolator;
+import android.view.animation.Interpolator;
 
 import com.android.internal.R;
 
@@ -67,6 +71,9 @@
 
     private static final boolean DBG_ANIMATOR_INFLATER = false;
 
+    // used to calculate changing configs for resource references
+    private static final TypedValue sTmpTypedValue = new TypedValue();
+
     /**
      * Loads an {@link Animator} object from a resource
      *
@@ -98,11 +105,34 @@
     /** @hide */
     public static Animator loadAnimator(Resources resources, Theme theme, int id,
             float pathErrorScale) throws NotFoundException {
-
+        final ConfigurationBoundResourceCache<Animator> animatorCache = resources
+                .getAnimatorCache();
+        Animator animator = animatorCache.get(id, theme);
+        if (animator != null) {
+            if (DBG_ANIMATOR_INFLATER) {
+                Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
+            }
+            return animator;
+        } else if (DBG_ANIMATOR_INFLATER) {
+            Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
+        }
         XmlResourceParser parser = null;
         try {
             parser = resources.getAnimation(id);
-            return createAnimatorFromXml(resources, theme, parser, pathErrorScale);
+            animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
+            if (animator != null) {
+                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
+                final ConstantState<Animator> constantState = animator.createConstantState();
+                if (constantState != null) {
+                    if (DBG_ANIMATOR_INFLATER) {
+                        Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
+                    }
+                    animatorCache.put(id, theme, constantState);
+                    // create a new animator so that cached version is never used by the user
+                    animator = constantState.newInstance(resources, theme);
+                }
+            }
+            return animator;
         } catch (XmlPullParserException ex) {
             Resources.NotFoundException rnf =
                     new Resources.NotFoundException("Can't load animation resource ID #0x" +
@@ -122,10 +152,29 @@
 
     public static StateListAnimator loadStateListAnimator(Context context, int id)
             throws NotFoundException {
+        final Resources resources = context.getResources();
+        final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
+                .getStateListAnimatorCache();
+        final Theme theme = context.getTheme();
+        StateListAnimator animator = cache.get(id, theme);
+        if (animator != null) {
+            return animator;
+        }
         XmlResourceParser parser = null;
         try {
-            parser = context.getResources().getAnimation(id);
-            return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
+            parser = resources.getAnimation(id);
+            animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
+            if (animator != null) {
+                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
+                final ConstantState<StateListAnimator> constantState = animator
+                        .createConstantState();
+                if (constantState != null) {
+                    cache.put(id, theme, constantState);
+                    // return a clone so that the animator in constant state is never used.
+                    animator = constantState.newInstance(resources, theme);
+                }
+            }
+            return animator;
         } catch (XmlPullParserException ex) {
             Resources.NotFoundException rnf =
                     new Resources.NotFoundException(
@@ -172,14 +221,13 @@
                         for (int i = 0; i < attributeCount; i++) {
                             int attrName = attributeSet.getAttributeNameResource(i);
                             if (attrName == R.attr.animation) {
-                                animator = loadAnimator(context,
-                                        attributeSet.getAttributeResourceValue(i, 0));
+                                final int animId = attributeSet.getAttributeResourceValue(i, 0);
+                                animator = loadAnimator(context, animId);
                             } else {
                                 states[stateIndex++] =
                                         attributeSet.getAttributeBooleanValue(i, false) ?
                                                 attrName : -attrName;
                             }
-
                         }
                         if (animator == null) {
                             animator = createAnimatorFromXml(context.getResources(),
@@ -192,7 +240,6 @@
                         }
                         stateListAnimator
                                 .addState(StateSet.trimStateSet(states, stateIndex), animator);
-
                     }
                     break;
             }
@@ -508,7 +555,6 @@
     private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
             AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize)
             throws XmlPullParserException, IOException {
-
         Animator anim = null;
         ArrayList<Animator> childAnims = null;
 
@@ -537,8 +583,8 @@
                 } else {
                     a = res.obtainAttributes(attrs, R.styleable.AnimatorSet);
                 }
-                int ordering = a.getInt(R.styleable.AnimatorSet_ordering,
-                        TOGETHER);
+                anim.appendChangingConfigurations(a.getChangingConfigurations());
+                int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER);
                 createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
                         pixelSize);
                 a.recycle();
@@ -565,7 +611,6 @@
                 parent.playSequentially(animsArray);
             }
         }
-
         return anim;
 
     }
@@ -591,7 +636,6 @@
     private static ValueAnimator loadAnimator(Resources res, Theme theme,
             AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
             throws NotFoundException {
-
         TypedArray arrayAnimator = null;
         TypedArray arrayObjectAnimator = null;
 
@@ -609,25 +653,37 @@
             } else {
                 arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
             }
+            anim.appendChangingConfigurations(arrayObjectAnimator.getChangingConfigurations());
         }
 
         if (anim == null) {
             anim = new ValueAnimator();
         }
+        anim.appendChangingConfigurations(arrayAnimator.getChangingConfigurations());
 
         parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale);
 
-        final int resID =
-                arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
+        final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
         if (resID > 0) {
-            anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID));
+            final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID);
+            if (interpolator instanceof BaseInterpolator) {
+                anim.appendChangingConfigurations(
+                        ((BaseInterpolator) interpolator).getChangingConfiguration());
+            }
+            anim.setInterpolator(interpolator);
         }
 
         arrayAnimator.recycle();
         if (arrayObjectAnimator != null) {
             arrayObjectAnimator.recycle();
         }
-
         return anim;
     }
+
+    private static int getChangingConfigs(Resources resources, int id) {
+        synchronized (sTmpTypedValue) {
+            resources.getValue(id, sTmpTypedValue, true);
+            return sTmpTypedValue.changingConfigurations;
+        }
+    }
 }
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 0aa8fdd..92762c3 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -241,6 +241,19 @@
     }
 
     /**
+     * @hide
+     */
+    @Override
+    public int getChangingConfigurations() {
+        int conf = super.getChangingConfigurations();
+        final int nodeCount = mNodes.size();
+        for (int i = 0; i < nodeCount; i ++) {
+            conf |= mNodes.get(i).animation.getChangingConfigurations();
+        }
+        return conf;
+    }
+
+    /**
      * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
      * of this AnimatorSet. The default value is null, which means that no interpolator
      * is set on this AnimatorSet. Setting the interpolator to any non-null value
@@ -628,23 +641,25 @@
          * manually, as we clone each Node (and its animation). The clone will then be sorted,
          * and will populate any appropriate lists, when it is started.
          */
+        final int nodeCount = mNodes.size();
         anim.mNeedsSort = true;
         anim.mTerminated = false;
         anim.mStarted = false;
         anim.mPlayingSet = new ArrayList<Animator>();
         anim.mNodeMap = new HashMap<Animator, Node>();
-        anim.mNodes = new ArrayList<Node>();
-        anim.mSortedNodes = new ArrayList<Node>();
+        anim.mNodes = new ArrayList<Node>(nodeCount);
+        anim.mSortedNodes = new ArrayList<Node>(nodeCount);
         anim.mReversible = mReversible;
         anim.mSetListener = null;
 
         // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
         // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
         // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
-        HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>(); // <old, new>
-        for (Node node : mNodes) {
+
+        for (int n = 0; n < nodeCount; n++) {
+            final Node node = mNodes.get(n);
             Node nodeClone = node.clone();
-            nodeCloneMap.put(node, nodeClone);
+            node.mTmpClone = nodeClone;
             anim.mNodes.add(nodeClone);
             anim.mNodeMap.put(nodeClone.animation, nodeClone);
             // Clear out the dependencies in the clone; we'll set these up manually later
@@ -652,40 +667,50 @@
             nodeClone.tmpDependencies = null;
             nodeClone.nodeDependents = null;
             nodeClone.nodeDependencies = null;
+
             // clear out any listeners that were set up by the AnimatorSet; these will
             // be set up when the clone's nodes are sorted
-            ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
+            final ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
             if (cloneListeners != null) {
-                ArrayList<AnimatorListener> listenersToRemove = null;
-                for (AnimatorListener listener : cloneListeners) {
+                for (int i = cloneListeners.size() - 1; i >= 0; i--) {
+                    final AnimatorListener listener = cloneListeners.get(i);
                     if (listener instanceof AnimatorSetListener) {
-                        if (listenersToRemove == null) {
-                            listenersToRemove = new ArrayList<AnimatorListener>();
-                        }
-                        listenersToRemove.add(listener);
-                    }
-                }
-                if (listenersToRemove != null) {
-                    for (AnimatorListener listener : listenersToRemove) {
-                        cloneListeners.remove(listener);
+                        cloneListeners.remove(i);
                     }
                 }
             }
         }
         // Now that we've cloned all of the nodes, we're ready to walk through their
         // dependencies, mapping the old dependencies to the new nodes
-        for (Node node : mNodes) {
-            Node nodeClone = nodeCloneMap.get(node);
+        for (int n = 0; n < nodeCount; n++) {
+            final Node node = mNodes.get(n);
+            final Node clone = node.mTmpClone;
             if (node.dependencies != null) {
-                for (Dependency dependency : node.dependencies) {
-                    Node clonedDependencyNode = nodeCloneMap.get(dependency.node);
-                    Dependency cloneDependency = new Dependency(clonedDependencyNode,
+                clone.dependencies = new ArrayList<Dependency>(node.dependencies.size());
+                final int depSize = node.dependencies.size();
+                for (int i = 0; i < depSize; i ++) {
+                    final Dependency dependency = node.dependencies.get(i);
+                    Dependency cloneDependency = new Dependency(dependency.node.mTmpClone,
                             dependency.rule);
-                    nodeClone.addDependency(cloneDependency);
+                    clone.dependencies.add(cloneDependency);
+                }
+            }
+            if (node.nodeDependents != null) {
+                clone.nodeDependents = new ArrayList<Node>(node.nodeDependents.size());
+                for (Node dep : node.nodeDependents) {
+                    clone.nodeDependents.add(dep.mTmpClone);
+                }
+            }
+            if (node.nodeDependencies != null) {
+                clone.nodeDependencies = new ArrayList<Node>(node.nodeDependencies.size());
+                for (Node dep : node.nodeDependencies) {
+                    clone.nodeDependencies.add(dep.mTmpClone);
                 }
             }
         }
-
+        for (int n = 0; n < nodeCount; n++) {
+            mNodes.get(n).mTmpClone = null;
+        }
         return anim;
     }
 
@@ -1017,6 +1042,11 @@
         public boolean done = false;
 
         /**
+         * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
+         */
+        private Node mTmpClone = null;
+
+        /**
          * Constructs the Node with the animation that it encapsulates. A Node has no
          * dependencies by default; dependencies are added via the addDependency()
          * method.
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index 12e5862..abac246 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -19,6 +19,7 @@
 import android.animation.Keyframe.FloatKeyframe;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate
@@ -47,8 +48,8 @@
 
     @Override
     public FloatKeyframeSet clone() {
-        ArrayList<Keyframe> keyframes = mKeyframes;
-        int numKeyframes = mKeyframes.size();
+        final List<Keyframe> keyframes = mKeyframes;
+        final int numKeyframes = mKeyframes.size();
         FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes];
         for (int i = 0; i < numKeyframes; ++i) {
             newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone();
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index 7a5b0ec..0ec5138 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -19,6 +19,7 @@
 import android.animation.Keyframe.IntKeyframe;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate
@@ -47,7 +48,7 @@
 
     @Override
     public IntKeyframeSet clone() {
-        ArrayList<Keyframe> keyframes = mKeyframes;
+        List<Keyframe> keyframes = mKeyframes;
         int numKeyframes = mKeyframes.size();
         IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes];
         for (int i = 0; i < numKeyframes; ++i) {
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 8d15db2..0e99bff 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -18,6 +18,8 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
+
 import android.animation.Keyframe.IntKeyframe;
 import android.animation.Keyframe.FloatKeyframe;
 import android.animation.Keyframe.ObjectKeyframe;
@@ -36,16 +38,16 @@
     Keyframe mFirstKeyframe;
     Keyframe mLastKeyframe;
     TimeInterpolator mInterpolator; // only used in the 2-keyframe case
-    ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
+    List<Keyframe> mKeyframes; // only used when there are not 2 keyframes
     TypeEvaluator mEvaluator;
 
 
     public KeyframeSet(Keyframe... keyframes) {
         mNumKeyframes = keyframes.length;
-        mKeyframes = new ArrayList<Keyframe>();
-        mKeyframes.addAll(Arrays.asList(keyframes));
-        mFirstKeyframe = mKeyframes.get(0);
-        mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
+        // immutable list
+        mKeyframes = Arrays.asList(keyframes);
+        mFirstKeyframe = keyframes[0];
+        mLastKeyframe = keyframes[mNumKeyframes - 1];
         mInterpolator = mLastKeyframe.getInterpolator();
     }
 
@@ -57,7 +59,7 @@
     public void invalidateCache() {
     }
 
-    public ArrayList<Keyframe> getKeyframes() {
+    public List<Keyframe> getKeyframes() {
         return mKeyframes;
     }
 
@@ -177,9 +179,9 @@
 
     @Override
     public KeyframeSet clone() {
-        ArrayList<Keyframe> keyframes = mKeyframes;
+        List<Keyframe> keyframes = mKeyframes;
         int numKeyframes = mKeyframes.size();
-        Keyframe[] newKeyframes = new Keyframe[numKeyframes];
+        final Keyframe[] newKeyframes = new Keyframe[numKeyframes];
         for (int i = 0; i < numKeyframes; ++i) {
             newKeyframes[i] = keyframes.get(i).clone();
         }
diff --git a/core/java/android/animation/Keyframes.java b/core/java/android/animation/Keyframes.java
index 6611c6c..c921466 100644
--- a/core/java/android/animation/Keyframes.java
+++ b/core/java/android/animation/Keyframes.java
@@ -16,6 +16,7 @@
 package android.animation;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This interface abstracts a collection of Keyframe objects and is called by
@@ -62,7 +63,7 @@
      * @return A list of all Keyframes contained by this. This may return null if this is
      * not made up of Keyframes.
      */
-    ArrayList<Keyframe> getKeyframes();
+    List<Keyframe> getKeyframes();
 
     Keyframes clone();
 
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index d372933..97426c3 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -27,6 +27,7 @@
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
@@ -791,7 +792,7 @@
             // check to make sure that mProperty is on the class of target
             try {
                 Object testValue = null;
-                ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+                List<Keyframe> keyframes = mKeyframes.getKeyframes();
                 int keyframeCount = keyframes == null ? 0 : keyframes.size();
                 for (int i = 0; i < keyframeCount; i++) {
                     Keyframe kf = keyframes.get(i);
@@ -814,7 +815,7 @@
         if (mSetter == null) {
             setupSetter(targetClass);
         }
-        ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+        List<Keyframe> keyframes = mKeyframes.getKeyframes();
         int keyframeCount = keyframes == null ? 0 : keyframes.size();
         for (int i = 0; i < keyframeCount; i++) {
             Keyframe kf = keyframes.get(i);
@@ -890,7 +891,7 @@
      * @param target The object which holds the start values that should be set.
      */
     void setupStartValue(Object target) {
-        ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+        List<Keyframe> keyframes = mKeyframes.getKeyframes();
         if (!keyframes.isEmpty()) {
             setupValue(target, keyframes.get(0));
         }
@@ -905,7 +906,7 @@
      * @param target The object which holds the start values that should be set.
      */
     void setupEndValue(Object target) {
-        ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+        List<Keyframe> keyframes = mKeyframes.getKeyframes();
         if (!keyframes.isEmpty()) {
             setupValue(target, keyframes.get(keyframes.size() - 1));
         }
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
index 7256a06..d49e914 100644
--- a/core/java/android/animation/StateListAnimator.java
+++ b/core/java/android/animation/StateListAnimator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.content.res.ConstantState;
 import android.util.StateSet;
 import android.view.View;
 
@@ -44,25 +45,31 @@
  * @attr ref android.R.styleable#DrawableStates_state_pressed
  * @attr ref android.R.styleable#StateListAnimatorItem_animation
  */
-public class StateListAnimator {
+public class StateListAnimator implements Cloneable {
 
-    private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
-
+    private ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
     private Tuple mLastMatch = null;
-
     private Animator mRunningAnimator = null;
-
     private WeakReference<View> mViewRef;
+    private StateListAnimatorConstantState mConstantState;
+    private AnimatorListenerAdapter mAnimatorListener;
+    private int mChangingConfigurations;
 
-    private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            animation.setTarget(null);
-            if (mRunningAnimator == animation) {
-                mRunningAnimator = null;
+    public StateListAnimator() {
+        initAnimatorListener();
+    }
+
+    private void initAnimatorListener() {
+        mAnimatorListener = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                animation.setTarget(null);
+                if (mRunningAnimator == animation) {
+                    mRunningAnimator = null;
+                }
             }
-        }
-    };
+        };
+    }
 
     /**
      * Associates the given animator with the provided drawable state specs so that it will be run
@@ -75,6 +82,7 @@
         Tuple tuple = new Tuple(specs, animator);
         tuple.mAnimator.addListener(mAnimatorListener);
         mTuples.add(tuple);
+        mChangingConfigurations |= animator.getChangingConfigurations();
     }
 
     /**
@@ -118,12 +126,35 @@
         for (int i = 0; i < size; i++) {
             mTuples.get(i).mAnimator.setTarget(null);
         }
-
         mViewRef = null;
         mLastMatch = null;
         mRunningAnimator = null;
     }
 
+    @Override
+    public StateListAnimator clone() {
+        try {
+            StateListAnimator clone = (StateListAnimator) super.clone();
+            clone.mTuples = new ArrayList<Tuple>(mTuples.size());
+            clone.mLastMatch = null;
+            clone.mRunningAnimator = null;
+            clone.mViewRef = null;
+            clone.mAnimatorListener = null;
+            clone.initAnimatorListener();
+            final int tupleSize = mTuples.size();
+            for (int i = 0; i < tupleSize; i++) {
+                final Tuple tuple = mTuples.get(i);
+                final Animator animatorClone = tuple.mAnimator.clone();
+                animatorClone.removeListener(mAnimatorListener);
+                clone.addState(tuple.mSpecs, animatorClone);
+            }
+            clone.setChangingConfigurations(getChangingConfigurations());
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError("cannot clone state list animator", e);
+        }
+    }
+
     /**
      * Called by View
      * @hide
@@ -182,6 +213,63 @@
     }
 
     /**
+     * Return a mask of the configuration parameters for which this animator may change, requiring
+     * that it be re-created.  The default implementation returns whatever was provided through
+     * {@link #setChangingConfigurations(int)} or 0 by default.
+     *
+     * @return Returns a mask of the changing configuration parameters, as defined by
+     * {@link android.content.pm.ActivityInfo}.
+     *
+     * @see android.content.pm.ActivityInfo
+     * @hide
+     */
+    public int getChangingConfigurations() {
+        return mChangingConfigurations;
+    }
+
+    /**
+     * Set a mask of the configuration parameters for which this animator may change, requiring
+     * that it should be recreated from resources instead of being cloned.
+     *
+     * @param configs A mask of the changing configuration parameters, as
+     * defined by {@link android.content.pm.ActivityInfo}.
+     *
+     * @see android.content.pm.ActivityInfo
+     * @hide
+     */
+    public void setChangingConfigurations(int configs) {
+        mChangingConfigurations = configs;
+    }
+
+    /**
+     * Sets the changing configurations value to the union of the current changing configurations
+     * and the provided configs.
+     * This method is called while loading the animator.
+     * @hide
+     */
+    public void appendChangingConfigurations(int configs) {
+        mChangingConfigurations |= configs;
+    }
+
+    /**
+     * Return a {@link android.content.res.ConstantState} instance that holds the shared state of
+     * this Animator.
+     * <p>
+     * This constant state is used to create new instances of this animator when needed. Default
+     * implementation creates a new {@link StateListAnimatorConstantState}. You can override this
+     * method to provide your custom logic or return null if you don't want this animator to be
+     * cached.
+     *
+     * @return The {@link android.content.res.ConstantState} associated to this Animator.
+     * @see android.content.res.ConstantState
+     * @see #clone()
+     * @hide
+     */
+    public ConstantState<StateListAnimator> createConstantState() {
+        return new StateListAnimatorConstantState(this);
+    }
+
+    /**
      * @hide
      */
     public static class Tuple {
@@ -209,4 +297,36 @@
             return mAnimator;
         }
     }
+
+    /**
+     * Creates a constant state which holds changing configurations information associated with the
+     * given Animator.
+     * <p>
+     * When new instance is called, default implementation clones the Animator.
+     */
+    private static class StateListAnimatorConstantState
+            extends ConstantState<StateListAnimator> {
+
+        final StateListAnimator mAnimator;
+
+        int mChangingConf;
+
+        public StateListAnimatorConstantState(StateListAnimator animator) {
+            mAnimator = animator;
+            mAnimator.mConstantState = this;
+            mChangingConf = mAnimator.getChangingConfigurations();
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConf;
+        }
+
+        @Override
+        public StateListAnimator newInstance() {
+            final StateListAnimator clone = mAnimator.clone();
+            clone.mConstantState = this;
+            return clone;
+        }
+    }
 }
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 0d17d67..07f79b8 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.content.res.ConfigurationBoundResourceCache;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
@@ -1289,12 +1290,7 @@
     public ValueAnimator clone() {
         final ValueAnimator anim = (ValueAnimator) super.clone();
         if (mUpdateListeners != null) {
-            ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
-            anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
-            int numListeners = oldListeners.size();
-            for (int i = 0; i < numListeners; ++i) {
-                anim.mUpdateListeners.add(oldListeners.get(i));
-            }
+            anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners);
         }
         anim.mSeekTime = -1;
         anim.mPlayingBackwards = false;
diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java
new file mode 100644
index 0000000..cde7e84
--- /dev/null
+++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java
@@ -0,0 +1,138 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* 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.
+*/
+package android.content.res;
+
+import android.util.ArrayMap;
+import android.util.LongSparseArray;
+import java.lang.ref.WeakReference;
+
+/**
+ * A Cache class which can be used to cache resource objects that are easy to clone but more
+ * expensive to inflate.
+ * @hide
+ */
+public class ConfigurationBoundResourceCache<T> {
+
+    private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>> mCache =
+            new ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>>();
+
+    final Resources mResources;
+
+    /**
+     * Creates a Resource cache for the given Resources instance.
+     *
+     * @param resources The Resource which can be used when creating new instances.
+     */
+    public ConfigurationBoundResourceCache(Resources resources) {
+        mResources = resources;
+    }
+
+    /**
+     * Adds a new item to the cache.
+     *
+     * @param key A custom key that uniquely identifies the resource.
+     * @param theme The Theme instance where this resource was loaded.
+     * @param constantState The constant state that can create new instances of the resource.
+     *
+     */
+    public void put(long key, Resources.Theme theme, ConstantState<T> constantState) {
+        if (constantState == null) {
+            return;
+        }
+        final String themeKey = theme == null ? "" : theme.getKey();
+        LongSparseArray<WeakReference<ConstantState<T>>> themedCache;
+        synchronized (this) {
+            themedCache = mCache.get(themeKey);
+            if (themedCache == null) {
+                themedCache = new LongSparseArray<WeakReference<ConstantState<T>>>(1);
+                mCache.put(themeKey, themedCache);
+            }
+            themedCache.put(key, new WeakReference<ConstantState<T>>(constantState));
+        }
+    }
+
+    /**
+     * If the resource is cached, creates a new instance of it and returns.
+     *
+     * @param key The long key which can be used to uniquely identify the resource.
+     * @param theme The The Theme instance where we want to load this resource.
+     *
+     * @return If this resources was loaded before, returns a new instance of it. Otherwise, returns
+     *         null.
+     */
+    public T get(long key, Resources.Theme theme) {
+        final String themeKey = theme != null ? theme.getKey() : "";
+        final LongSparseArray<WeakReference<ConstantState<T>>> themedCache;
+        final WeakReference<ConstantState<T>> wr;
+        synchronized (this) {
+            themedCache = mCache.get(themeKey);
+            if (themedCache == null) {
+                return null;
+            }
+            wr = themedCache.get(key);
+        }
+        if (wr == null) {
+            return null;
+        }
+        final ConstantState entry = wr.get();
+        if (entry != null) {
+            return  (T) entry.newInstance(mResources, theme);
+        } else {  // our entry has been purged
+            synchronized (this) {
+                // there is a potential race condition here where this entry may be put in
+                // another thread. But we prefer it to minimize lock duration
+                themedCache.delete(key);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Users of ConfigurationBoundResourceCache must call this method whenever a configuration
+     * change happens. On this callback, the cache invalidates all resources that are not valid
+     * anymore.
+     *
+     * @param configChanges The configuration changes
+     */
+    public void onConfigurationChange(final int configChanges) {
+        synchronized (this) {
+            final int size = mCache.size();
+            for (int i = size - 1; i >= 0; i--) {
+                final LongSparseArray<WeakReference<ConstantState<T>>>
+                        themeCache = mCache.valueAt(i);
+                onConfigurationChangeInt(themeCache, configChanges);
+                if (themeCache.size() == 0) {
+                    mCache.removeAt(i);
+                }
+            }
+        }
+    }
+
+    private void onConfigurationChangeInt(
+            final LongSparseArray<WeakReference<ConstantState<T>>> themeCache,
+            final int configChanges) {
+        final int size = themeCache.size();
+        for (int i = size - 1; i >= 0; i--) {
+            final WeakReference<ConstantState<T>> wr = themeCache.valueAt(i);
+            final ConstantState<T> constantState = wr.get();
+            if (constantState == null || Configuration.needNewResources(
+                    configChanges, constantState.getChangingConfigurations())) {
+                themeCache.removeAt(i);
+            }
+        }
+    }
+
+}
diff --git a/core/java/android/content/res/ConstantState.java b/core/java/android/content/res/ConstantState.java
new file mode 100644
index 0000000..ee609df
--- /dev/null
+++ b/core/java/android/content/res/ConstantState.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* 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.
+*/
+package android.content.res;
+
+/**
+ * A cache class that can provide new instances of a particular resource which may change
+ * depending on the current {@link Resources.Theme} or {@link Configuration}.
+ * <p>
+ * A constant state should be able to return a bitmask of changing configurations, which
+ * identifies the type of configuration changes that may invalidate this resource. These
+ * configuration changes can be obtained from {@link android.util.TypedValue}. Entities such as
+ * {@link android.animation.Animator} also provide a changing configuration method to include
+ * their dependencies (e.g. An AnimatorSet's changing configuration is the union of the
+ * changing configurations of each Animator in the set)
+ * @hide
+ */
+abstract public class ConstantState<T> {
+
+    /**
+     * Return a bit mask of configuration changes that will impact
+     * this resource (and thus require completely reloading it).
+     */
+    abstract public int getChangingConfigurations();
+
+    /**
+     * Create a new instance without supplying resources the caller
+     * is running in.
+     */
+    public abstract T newInstance();
+
+    /**
+     * Create a new instance from its constant state.  This
+     * must be implemented for resources that change based on the target
+     * density of their caller (that is depending on whether it is
+     * in compatibility mode).
+     */
+    public T newInstance(Resources res) {
+        return newInstance();
+    }
+
+    /**
+     * Create a new instance from its constant state.  This must be
+     * implemented for resources that can have a theme applied.
+     */
+    public T newInstance(Resources res, Resources.Theme theme) {
+        return newInstance(res);
+    }
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index e34ce3e..6e9efe1 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,6 +16,8 @@
 
 package android.content.res;
 
+import android.animation.Animator;
+import android.animation.StateListAnimator;
 import android.util.Pools.SynchronizedPool;
 import android.view.ViewDebug;
 import com.android.internal.util.XmlUtils;
@@ -115,6 +117,10 @@
             new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
     private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache =
             new LongSparseArray<WeakReference<ColorStateList>>();
+    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
+            new ConfigurationBoundResourceCache<Animator>(this);
+    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
+            new ConfigurationBoundResourceCache<StateListAnimator>(this);
 
     private TypedValue mTmpValue = new TypedValue();
     private boolean mPreloading;
@@ -183,6 +189,24 @@
     }
 
     /**
+     * Used by AnimatorInflater.
+     *
+     * @hide
+     */
+    public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
+        return mAnimatorCache;
+    }
+
+    /**
+     * Used by AnimatorInflater.
+     *
+     * @hide
+     */
+    public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
+        return mStateListAnimatorCache;
+    }
+
+    /**
      * This exception is thrown by the resource APIs when a requested resource
      * can not be found.
      */
@@ -1761,23 +1785,7 @@
             // the framework.
             mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
 
-            int configChanges = 0xfffffff;
-            if (config != null) {
-                mTmpConfig.setTo(config);
-                int density = config.densityDpi;
-                if (density == Configuration.DENSITY_DPI_UNDEFINED) {
-                    density = mMetrics.noncompatDensityDpi;
-                }
-
-                mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
-
-                if (mTmpConfig.locale == null) {
-                    mTmpConfig.locale = Locale.getDefault();
-                    mTmpConfig.setLayoutDirection(mTmpConfig.locale);
-                }
-                configChanges = mConfiguration.updateFrom(mTmpConfig);
-                configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
-            }
+            int configChanges = calcConfigChanges(config);
             if (mConfiguration.locale == null) {
                 mConfiguration.locale = Locale.getDefault();
                 mConfiguration.setLayoutDirection(mConfiguration.locale);
@@ -1825,6 +1833,8 @@
 
             clearDrawableCachesLocked(mDrawableCache, configChanges);
             clearDrawableCachesLocked(mColorDrawableCache, configChanges);
+            mAnimatorCache.onConfigurationChange(configChanges);
+            mStateListAnimatorCache.onConfigurationChange(configChanges);
 
             mColorStateListCache.clear();
 
@@ -1837,6 +1847,30 @@
         }
     }
 
+    /**
+     * Called by ConfigurationBoundResourceCacheTest via reflection.
+     */
+    private int calcConfigChanges(Configuration config) {
+        int configChanges = 0xfffffff;
+        if (config != null) {
+            mTmpConfig.setTo(config);
+            int density = config.densityDpi;
+            if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+                density = mMetrics.noncompatDensityDpi;
+            }
+
+            mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
+
+            if (mTmpConfig.locale == null) {
+                mTmpConfig.locale = Locale.getDefault();
+                mTmpConfig.setLayoutDirection(mTmpConfig.locale);
+            }
+            configChanges = mConfiguration.updateFrom(mTmpConfig);
+            configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+        }
+        return configChanges;
+    }
+
     private void clearDrawableCachesLocked(
             ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
             int configChanges) {
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 58f0fc0..4fa0593 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -21,7 +21,9 @@
 import android.os.Parcel;
 import android.system.ErrnoException;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.net.DatagramSocket;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.MalformedURLException;
@@ -264,18 +266,40 @@
     }
 
     /**
+     * Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the
+     * socket will be sent on this {@code Network}, irrespective of any process-wide network binding
+     * set by {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be
+     * connected.
+     */
+    public void bindSocket(DatagramSocket socket) throws IOException {
+        // Apparently, the kernel doesn't update a connected UDP socket's routing upon mark changes.
+        if (socket.isConnected()) {
+            throw new SocketException("Socket is connected");
+        }
+        // Query a property of the underlying socket to ensure that the socket's file descriptor
+        // exists, is available to bind to a network and is not closed.
+        socket.getReuseAddress();
+        bindSocketFd(socket.getFileDescriptor$());
+    }
+
+    /**
      * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket
      * will be sent on this {@code Network}, irrespective of any process-wide network binding set by
      * {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be connected.
      */
     public void bindSocket(Socket socket) throws IOException {
+        // Apparently, the kernel doesn't update a connected TCP socket's routing upon mark changes.
         if (socket.isConnected()) {
             throw new SocketException("Socket is connected");
         }
-        // Query a property of the underlying socket to ensure the underlying
-        // socket exists so a file descriptor is available to bind to a network.
+        // Query a property of the underlying socket to ensure that the socket's file descriptor
+        // exists, is available to bind to a network and is not closed.
         socket.getReuseAddress();
-        int err = NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), netId);
+        bindSocketFd(socket.getFileDescriptor$());
+    }
+
+    private void bindSocketFd(FileDescriptor fd) throws IOException {
+        int err = NetworkUtils.bindSocketToNetwork(fd.getInt$(), netId);
         if (err != 0) {
             // bindSocketToNetwork returns negative errno.
             throw new ErrnoException("Binding socket to network " + netId, -err)
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 75c435e..98a1f05 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5095,6 +5095,12 @@
         public static final String AIRPLANE_MODE_ON = "airplane_mode_on";
 
         /**
+         * Whether Theater Mode is on.
+         * {@hide}
+         */
+        public static final String THEATER_MODE_ON = "theater_mode_on";
+
+        /**
          * Constant for use in AIRPLANE_MODE_RADIOS to specify Bluetooth radio.
          */
         public static final String RADIO_BLUETOOTH = "bluetooth";
@@ -6593,7 +6599,7 @@
          * Type: int (0 for false, 1 for true)
          * @hide
          */
-        public static final String VOLTE_VT_ENABLED = "volte_vt_enabled";
+        public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
 
         /**
          * Settings to backup. This is here so that it's in the same place as the settings
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index 0da5fb6..2c55141 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -16,6 +16,7 @@
 
 package android.transition;
 
+import android.animation.AnimatorSet;
 import android.content.Context;
 import android.graphics.PointF;
 
@@ -31,7 +32,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.IntProperty;
 import android.util.Property;
 import android.view.View;
 import android.view.ViewGroup;
@@ -77,6 +77,32 @@
                 }
     };
 
+    private static final Property<ViewBounds, PointF> TOP_LEFT_PROPERTY =
+            new Property<ViewBounds, PointF>(PointF.class, "topLeft") {
+                @Override
+                public void set(ViewBounds viewBounds, PointF topLeft) {
+                    viewBounds.setTopLeft(topLeft);
+                }
+
+                @Override
+                public PointF get(ViewBounds viewBounds) {
+                    return null;
+                }
+            };
+
+    private static final Property<ViewBounds, PointF> BOTTOM_RIGHT_PROPERTY =
+            new Property<ViewBounds, PointF>(PointF.class, "bottomRight") {
+                @Override
+                public void set(ViewBounds viewBounds, PointF bottomRight) {
+                    viewBounds.setBottomRight(bottomRight);
+                }
+
+                @Override
+                public PointF get(ViewBounds viewBounds) {
+                    return null;
+                }
+            };
+
     int[] tempLocation = new int[2];
     boolean mResizeClip = false;
     boolean mReparent = false;
@@ -189,36 +215,20 @@
             }
             if (numChanges > 0) {
                 if (!mResizeClip) {
-                    Animator anim;
-                    if (startWidth == endWidth && startHeight == endHeight) {
-                        view.offsetLeftAndRight(startLeft - view.getLeft());
-                        view.offsetTopAndBottom(startTop - view.getTop());
-                        Path positionPath = getPathMotion().getPath(0, 0, endLeft - startLeft,
-                                endTop - startTop);
-                        anim = ObjectAnimator.ofInt(view, new HorizontalOffsetProperty(),
-                                new VerticalOffsetProperty(), positionPath);
-                    } else {
-                        if (startLeft != endLeft) view.setLeft(startLeft);
-                        if (startTop != endTop) view.setTop(startTop);
-                        if (startRight != endRight) view.setRight(startRight);
-                        if (startBottom != endBottom) view.setBottom(startBottom);
-                        ObjectAnimator topLeftAnimator = null;
-                        if (startLeft != endLeft || startTop != endTop) {
-                            Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
-                                    endLeft, endTop);
-                            topLeftAnimator = ObjectAnimator
-                                    .ofInt(view, "left", "top", topLeftPath);
-                        }
-                        ObjectAnimator bottomRightAnimator = null;
-                        if (startRight != endRight || startBottom != endBottom) {
-                            Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
-                                    endRight, endBottom);
-                            bottomRightAnimator = ObjectAnimator.ofInt(view, "right", "bottom",
-                                    bottomRightPath);
-                        }
-                        anim = TransitionUtils.mergeAnimators(topLeftAnimator,
-                                bottomRightAnimator);
-                    }
+                    view.setLeftTopRightBottom(startLeft, startTop, startRight, startBottom);
+                    ViewBounds viewBounds = new ViewBounds(view);
+                    Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
+                            endLeft, endTop);
+                    ObjectAnimator topLeftAnimator = ObjectAnimator
+                            .ofObject(viewBounds, TOP_LEFT_PROPERTY, null, topLeftPath);
+
+                    Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
+                            endRight, endBottom);
+                    ObjectAnimator bottomRightAnimator = ObjectAnimator.ofObject(viewBounds,
+                            BOTTOM_RIGHT_PROPERTY, null, bottomRightPath);
+                    AnimatorSet anim = new AnimatorSet();
+                    anim.playTogether(topLeftAnimator, bottomRightAnimator);
+
                     if (view.getParent() instanceof ViewGroup) {
                         final ViewGroup parent = (ViewGroup) view.getParent();
                         parent.suppressLayout(true);
@@ -357,47 +367,41 @@
         return null;
     }
 
-    private abstract static class OffsetProperty extends IntProperty<View> {
-        int mPreviousValue;
+    private static class ViewBounds {
+        private int mLeft;
+        private int mTop;
+        private int mRight;
+        private int mBottom;
+        private boolean mIsTopLeftSet;
+        private boolean mIsBottomRightSet;
+        private View mView;
 
-        public OffsetProperty(String name) {
-            super(name);
+        public ViewBounds(View view) {
+            mView = view;
         }
 
-        @Override
-        public void setValue(View view, int value) {
-            int offset = value - mPreviousValue;
-            offsetBy(view, offset);
-            mPreviousValue = value;
+        public void setTopLeft(PointF topLeft) {
+            mLeft = Math.round(topLeft.x);
+            mTop = Math.round(topLeft.y);
+            mIsTopLeftSet = true;
+            if (mIsBottomRightSet) {
+                setLeftTopRightBottom();
+            }
         }
 
-        @Override
-        public Integer get(View object) {
-            return null;
+        public void setBottomRight(PointF bottomRight) {
+            mRight = Math.round(bottomRight.x);
+            mBottom = Math.round(bottomRight.y);
+            mIsBottomRightSet = true;
+            if (mIsTopLeftSet) {
+                setLeftTopRightBottom();
+            }
         }
 
-        protected abstract void offsetBy(View view, int by);
-    }
-
-    private static class HorizontalOffsetProperty extends OffsetProperty {
-        public HorizontalOffsetProperty() {
-            super("offsetLeftAndRight");
-        }
-
-        @Override
-        protected void offsetBy(View view, int by) {
-            view.offsetLeftAndRight(by);
-        }
-    }
-
-    private static class VerticalOffsetProperty extends OffsetProperty {
-        public VerticalOffsetProperty() {
-            super("offsetTopAndBottom");
-        }
-
-        @Override
-        protected void offsetBy(View view, int by) {
-            view.offsetTopAndBottom(by);
+        private void setLeftTopRightBottom() {
+            mView.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+            mIsTopLeftSet = false;
+            mIsBottomRightSet = false;
         }
     }
 }
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 132e25c..562d138 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -311,7 +311,10 @@
      * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
      * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
      * unsupported drawing operations</a> for a list of what is and isn't
-     * supported in a hardware-accelerated canvas.
+     * supported in a hardware-accelerated canvas. It is also required to
+     * fully cover the surface every time {@link #lockHardwareCanvas()} is
+     * called as the buffer is not preserved between frames. Partial updates
+     * are not supported.
      *
      * @return A canvas for drawing into the surface.
      *
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8e58cd6..8664a24 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15699,6 +15699,14 @@
         return changed;
     }
 
+    /**
+     * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}.
+     * @hide
+     */
+    public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
+        setFrame(left, top, right, bottom);
+    }
+
     private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) {
         onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
         if (mOverlay != null) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 63ab7d2..ef073b5 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -24,7 +24,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.media.session.MediaController;
-import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -801,9 +800,6 @@
     public void setFlags(int flags, int mask) {
         final WindowManager.LayoutParams attrs = getAttributes();
         attrs.flags = (attrs.flags&~mask) | (flags&mask);
-        if ((mask&WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0) {
-            attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
-        }
         mForcedWindowFlags |= mask;
         dispatchWindowAttributesChanged(attrs);
     }
@@ -817,6 +813,15 @@
     /**
      * {@hide}
      */
+    protected void setNeedsMenuKey(int value) {
+        final WindowManager.LayoutParams attrs = getAttributes();
+        attrs.needsMenuKey = value;
+        dispatchWindowAttributesChanged(attrs);
+    }
+
+    /**
+     * {@hide}
+     */
     protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
         if (mCallback != null) {
             mCallback.onWindowAttributesChanged(attrs);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 75c9ebd..3f84c9b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -878,9 +878,6 @@
          */
         public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;
 
-        // ----- HIDDEN FLAGS.
-        // These start at the high bit and go down.
-
         /**
          * Flag for a window in local focus mode.
          * Window in local focus mode can control focus independent of window manager using
@@ -903,17 +900,12 @@
         public static final int FLAG_SLIPPERY = 0x20000000;
 
         /**
-         * Flag for a window belonging to an activity that responds to {@link KeyEvent#KEYCODE_MENU}
-         * and therefore needs a Menu key. For devices where Menu is a physical button this flag is
-         * ignored, but on devices where the Menu key is drawn in software it may be hidden unless
-         * this flag is set.
-         *
-         * (Note that Action Bars, when available, are the preferred way to offer additional
-         * functions otherwise accessed via an options menu.)
-         *
-         * {@hide}
+         * Window flag: When requesting layout with an attached window, the attached window may
+         * overlap with the screen decorations of the parent window such as the navigation bar. By
+         * including this flag, the window manager will layout the attached window within the decor
+         * frame of the parent window such that it doesn't overlap with screen decorations.
          */
-        public static final int FLAG_NEEDS_MENU_KEY = 0x40000000;
+        public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000;
 
         /**
          * Flag indicating that this Window is responsible for drawing the background for the
@@ -1056,16 +1048,6 @@
          */
         public static final int PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS = 0x00000004;
 
-        /**
-         * This is set for a window that has explicitly specified its
-         * FLAG_NEEDS_MENU_KEY, so we know the value on this window is the
-         * appropriate one to use.  If this is not set, we should look at
-         * windows behind it to determine the appropriate value.
-         *
-         * @hide
-         */
-        public static final int PRIVATE_FLAG_SET_NEEDS_MENU_KEY = 0x00000008;
-
         /** In a multiuser system if this flag is set and the owner is a system process then this
          * window will appear on all user screens. This overrides the default behavior of window
          * types that normally only appear on the owning user's screen. Refer to each window type
@@ -1113,6 +1095,45 @@
         public int privateFlags;
 
         /**
+         * Value for {@link #needsMenuKey} for a window that has not explicitly specified if it
+         * needs {@link #NEEDS_MENU_SET_TRUE} or doesn't need {@link #NEEDS_MENU_SET_FALSE} a menu
+         * key. For this case, we should look at windows behind it to determine the appropriate
+         * value.
+         *
+         * @hide
+         */
+        public static final int NEEDS_MENU_UNSET = 0;
+
+        /**
+         * Value for {@link #needsMenuKey} for a window that has explicitly specified it needs a
+         * menu key.
+         *
+         * @hide
+         */
+        public static final int NEEDS_MENU_SET_TRUE = 1;
+
+        /**
+         * Value for {@link #needsMenuKey} for a window that has explicitly specified it doesn't
+         * needs a menu key.
+         *
+         * @hide
+         */
+        public static final int NEEDS_MENU_SET_FALSE = 2;
+
+        /**
+         * State variable for a window belonging to an activity that responds to
+         * {@link KeyEvent#KEYCODE_MENU} and therefore needs a Menu key. For devices where Menu is a
+         * physical button this variable is ignored, but on devices where the Menu key is drawn in
+         * software it may be hidden unless this variable is set to {@link #NEEDS_MENU_SET_TRUE}.
+         *
+         *  (Note that Action Bars, when available, are the preferred way to offer additional
+         * functions otherwise accessed via an options menu.)
+         *
+         * {@hide}
+         */
+        public int needsMenuKey = NEEDS_MENU_UNSET;
+
+        /**
          * Given a particular set of window manager flags, determine whether
          * such a window may be a target for an input method when it has
          * focus.  In particular, this checks the
@@ -1120,9 +1141,9 @@
          * flags and returns true if the combination of the two corresponds
          * to a window that needs to be behind the input method so that the
          * user can type into it.
-         * 
+         *
          * @param flags The current window manager flags.
-         * 
+         *
          * @return Returns true if such a window should be behind/interact
          * with an input method, false if not.
          */
@@ -1587,14 +1608,15 @@
             out.writeInt(surfaceInsets.top);
             out.writeInt(surfaceInsets.right);
             out.writeInt(surfaceInsets.bottom);
+            out.writeInt(needsMenuKey);
         }
-        
+
         public static final Parcelable.Creator<LayoutParams> CREATOR
                     = new Parcelable.Creator<LayoutParams>() {
             public LayoutParams createFromParcel(Parcel in) {
                 return new LayoutParams(in);
             }
-    
+
             public LayoutParams[] newArray(int size) {
                 return new LayoutParams[size];
             }
@@ -1634,8 +1656,9 @@
             surfaceInsets.top = in.readInt();
             surfaceInsets.right = in.readInt();
             surfaceInsets.bottom = in.readInt();
+            needsMenuKey = in.readInt();
         }
-    
+
         @SuppressWarnings({"PointlessBitwiseExpression"})
         public static final int LAYOUT_CHANGED = 1<<0;
         public static final int TYPE_CHANGED = 1<<1;
@@ -1669,14 +1692,16 @@
         /** {@hide} */
         public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21;
         /** {@hide} */
+        public static final int NEEDS_MENU_KEY_CHANGED = 1 << 22;
+        /** {@hide} */
         public static final int EVERYTHING_CHANGED = 0xffffffff;
 
         // internal buffer to backup/restore parameters under compatibility mode.
         private int[] mCompatibilityParamsBackup = null;
-        
+
         public final int copyFrom(LayoutParams o) {
             int changes = 0;
-    
+
             if (width != o.width) {
                 width = o.width;
                 changes |= LAYOUT_CHANGED;
@@ -1813,9 +1838,14 @@
                 changes |= SURFACE_INSETS_CHANGED;
             }
 
+            if (needsMenuKey != o.needsMenuKey) {
+                needsMenuKey = o.needsMenuKey;
+                changes |= NEEDS_MENU_KEY_CHANGED;
+            }
+
             return changes;
         }
-    
+
         @Override
         public String debug(String output) {
             output += "Contents of " + this + ":";
@@ -1919,6 +1949,10 @@
             if (!surfaceInsets.equals(Insets.NONE)) {
                 sb.append(" surfaceInsets=").append(surfaceInsets);
             }
+            if (needsMenuKey != NEEDS_MENU_UNSET) {
+                sb.append(" needsMenuKey=");
+                sb.append(needsMenuKey);
+            }
             sb.append('}');
             return sb.toString();
         }
diff --git a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
index ed6949a..21d5a5b 100644
--- a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
@@ -26,17 +26,17 @@
 /**
  * An interpolator where the rate of change starts and ends slowly but
  * accelerates through the middle.
- * 
  */
 @HasNativeInterpolator
-public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class AccelerateDecelerateInterpolator extends BaseInterpolator
+        implements NativeInterpolatorFactory {
     public AccelerateDecelerateInterpolator() {
     }
-    
+
     @SuppressWarnings({"UnusedDeclaration"})
     public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
     }
-    
+
     public float getInterpolation(float input) {
         return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
     }
diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java
index 1c75f16..6c8d7b1 100644
--- a/core/java/android/view/animation/AccelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateInterpolator.java
@@ -33,7 +33,7 @@
  *
  */
 @HasNativeInterpolator
-public class AccelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     private final float mFactor;
     private final double mDoubleFactor;
 
@@ -70,7 +70,7 @@
 
         mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
         mDoubleFactor = 2 * mFactor;
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index af4e04f..606c83e 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -321,7 +321,7 @@
     private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser)
             throws XmlPullParserException, IOException {
 
-        Interpolator interpolator = null;
+        BaseInterpolator interpolator = null;
 
         // Make sure we are on a start tag.
         int type;
@@ -361,10 +361,7 @@
             } else {
                 throw new RuntimeException("Unknown interpolator name: " + parser.getName());
             }
-
         }
-
         return interpolator;
-
     }
 }
diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
index fe756bd..fb66c31 100644
--- a/core/java/android/view/animation/AnticipateInterpolator.java
+++ b/core/java/android/view/animation/AnticipateInterpolator.java
@@ -31,7 +31,7 @@
  * An interpolator where the change starts backward then flings forward.
  */
 @HasNativeInterpolator
-public class AnticipateInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     private final float mTension;
 
     public AnticipateInterpolator() {
@@ -60,9 +60,8 @@
             a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator);
         }
 
-        mTension =
-                a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);
-
+        mTension = a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
index 78e5acf..1af72da 100644
--- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java
+++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
@@ -35,7 +35,8 @@
  * the target value and finally goes back to the final value.
  */
 @HasNativeInterpolator
-public class AnticipateOvershootInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class AnticipateOvershootInterpolator extends BaseInterpolator
+        implements NativeInterpolatorFactory {
     private final float mTension;
 
     public AnticipateOvershootInterpolator() {
@@ -78,7 +79,7 @@
 
         mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
                 a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/BaseInterpolator.java b/core/java/android/view/animation/BaseInterpolator.java
new file mode 100644
index 0000000..9c0014c
--- /dev/null
+++ b/core/java/android/view/animation/BaseInterpolator.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package android.view.animation;
+
+/**
+ * An abstract class which is extended by default interpolators.
+ */
+abstract public class BaseInterpolator implements Interpolator {
+    private int mChangingConfiguration;
+    /**
+     * @hide
+     */
+    public int getChangingConfiguration() {
+        return mChangingConfiguration;
+    }
+
+    /**
+     * @hide
+     */
+    void setChangingConfiguration(int changingConfiguration) {
+        mChangingConfiguration = changingConfiguration;
+    }
+}
diff --git a/core/java/android/view/animation/BounceInterpolator.java b/core/java/android/view/animation/BounceInterpolator.java
index 9d8ca90..909eaa4 100644
--- a/core/java/android/view/animation/BounceInterpolator.java
+++ b/core/java/android/view/animation/BounceInterpolator.java
@@ -27,7 +27,7 @@
  * An interpolator where the change bounces at the end.
  */
 @HasNativeInterpolator
-public class BounceInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class BounceInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     public BounceInterpolator() {
     }
 
diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java
index 3114aa3..663c109 100644
--- a/core/java/android/view/animation/CycleInterpolator.java
+++ b/core/java/android/view/animation/CycleInterpolator.java
@@ -33,7 +33,7 @@
  *
  */
 @HasNativeInterpolator
-public class CycleInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class CycleInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     public CycleInterpolator(float cycles) {
         mCycles = cycles;
     }
@@ -52,7 +52,7 @@
         }
 
         mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f);
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index 674207c..f426f60 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -33,7 +33,7 @@
  *
  */
 @HasNativeInterpolator
-public class DecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     public DecelerateInterpolator() {
     }
 
@@ -62,7 +62,7 @@
         }
 
         mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f);
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/LinearInterpolator.java b/core/java/android/view/animation/LinearInterpolator.java
index 552c611..2a047b4 100644
--- a/core/java/android/view/animation/LinearInterpolator.java
+++ b/core/java/android/view/animation/LinearInterpolator.java
@@ -25,17 +25,16 @@
 
 /**
  * An interpolator where the rate of change is constant
- *
  */
 @HasNativeInterpolator
-public class LinearInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
 
     public LinearInterpolator() {
     }
-    
+
     public LinearInterpolator(Context context, AttributeSet attrs) {
     }
-    
+
     public float getInterpolation(float input) {
         return input;
     }
diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java
index d6c2808..306688a 100644
--- a/core/java/android/view/animation/OvershootInterpolator.java
+++ b/core/java/android/view/animation/OvershootInterpolator.java
@@ -32,7 +32,7 @@
  * then comes back.
  */
 @HasNativeInterpolator
-public class OvershootInterpolator implements Interpolator, NativeInterpolatorFactory {
+public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
     private final float mTension;
 
     public OvershootInterpolator() {
@@ -61,9 +61,8 @@
             a = res.obtainAttributes(attrs, R.styleable.OvershootInterpolator);
         }
 
-        mTension =
-                a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
-
+        mTension = a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java
index 945ecf0..eec5555 100644
--- a/core/java/android/view/animation/PathInterpolator.java
+++ b/core/java/android/view/animation/PathInterpolator.java
@@ -42,7 +42,7 @@
  *     path.lineTo(1f, 1f);
  * </pre></blockquote></p>
  */
-public class PathInterpolator implements Interpolator {
+public class PathInterpolator extends BaseInterpolator {
 
     // This governs how accurate the approximation of the Path is.
     private static final float PRECISION = 0.002f;
@@ -98,7 +98,7 @@
             a = res.obtainAttributes(attrs, R.styleable.PathInterpolator);
         }
         parseInterpolatorFromTypeArray(a);
-
+        setChangingConfiguration(a.getChangingConfigurations());
         a.recycle();
     }
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 0439168..4aebaae 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4653,7 +4653,7 @@
         if (mPositionScroller == null) {
             mPositionScroller = createPositionScroller();
         }
-        mPositionScroller.startWithOffset(position, offset, offset);
+        mPositionScroller.startWithOffset(position, offset);
     }
 
     /**
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index b9f891c..5fa6e60 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -215,7 +215,12 @@
     private boolean mDesiredFocusableState;
     private boolean mDesiredFocusableInTouchModeState;
 
+    /** Lazily-constructed runnable for dispatching selection events. */
     private SelectionNotifier mSelectionNotifier;
+
+    /** Selection notifier that's waiting for the next layout pass. */
+    private SelectionNotifier mPendingSelectionNotifier;
+
     /**
      * When set to true, calls to requestLayout() will not propagate up the parent hierarchy.
      * This is used to layout the children during a layout pass.
@@ -854,39 +859,50 @@
 
     private class SelectionNotifier implements Runnable {
         public void run() {
+            mPendingSelectionNotifier = null;
+
             if (mDataChanged) {
-                // Data has changed between when this SelectionNotifier
-                // was posted and now. We need to wait until the AdapterView
-                // has been synched to the new data.
+                // Data has changed between when this SelectionNotifier was
+                // posted and now. Postpone the notification until the next
+                // layout is complete and we run checkSelectionChanged().
                 if (getAdapter() != null) {
-                    post(this);
+                    mPendingSelectionNotifier = this;
                 }
             } else {
-                fireOnSelected();
-                performAccessibilityActionsOnSelected();
+                dispatchOnItemSelected();
             }
         }
     }
 
     void selectionChanged() {
+        // We're about to post or run the selection notifier, so we don't need
+        // a pending notifier.
+        mPendingSelectionNotifier = null;
+
         if (mOnItemSelectedListener != null
                 || AccessibilityManager.getInstance(mContext).isEnabled()) {
             if (mInLayout || mBlockLayoutRequests) {
                 // If we are in a layout traversal, defer notification
                 // by posting. This ensures that the view tree is
-                // in a consistent state and is able to accomodate
+                // in a consistent state and is able to accommodate
                 // new layout or invalidate requests.
                 if (mSelectionNotifier == null) {
                     mSelectionNotifier = new SelectionNotifier();
+                } else {
+                    removeCallbacks(mSelectionNotifier);
                 }
                 post(mSelectionNotifier);
             } else {
-                fireOnSelected();
-                performAccessibilityActionsOnSelected();
+                dispatchOnItemSelected();
             }
         }
     }
 
+    private void dispatchOnItemSelected() {
+        fireOnSelected();
+        performAccessibilityActionsOnSelected();
+    }
+
     private void fireOnSelected() {
         if (mOnItemSelectedListener == null) {
             return;
@@ -1042,12 +1058,22 @@
         notifySubtreeAccessibilityStateChangedIfNeeded();
     }
 
+    /**
+     * Called after layout to determine whether the selection position needs to
+     * be updated. Also used to fire any pending selection events.
+     */
     void checkSelectionChanged() {
         if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
             selectionChanged();
             mOldSelectedPosition = mSelectedPosition;
             mOldSelectedRowId = mSelectedRowId;
         }
+
+        // If we have a pending selection notification -- and we won't if we
+        // just fired one in selectionChanged() -- run it now.
+        if (mPendingSelectionNotifier != null) {
+            mPendingSelectionNotifier.run();
+        }
     }
 
     /**
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index f90a9fe..75dfcca 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1120,6 +1120,9 @@
 
     /** @hide */
     public void animateTransform(Matrix matrix) {
+        if (mDrawable == null) {
+            return;
+        }
         if (matrix == null) {
             mDrawable.setBounds(0, 0, getWidth(), getHeight());
         } else {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 41d3e320..54a7940 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -97,9 +97,11 @@
     private boolean mAllowScrollingAnchorParent = true;
     private boolean mLayoutInsetDecor = false;
     private boolean mNotTouchModal;
+    private boolean mAttachedInDecor = true;
+    private boolean mAttachedInDecorSet = false;
 
     private OnTouchListener mTouchInterceptor;
-    
+
     private int mWidthMode;
     private int mWidth;
     private int mLastWidth;
@@ -316,6 +318,7 @@
             mContext = contentView.getContext();
             mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         }
+
         setContentView(contentView);
         setWidth(width);
         setHeight(height);
@@ -373,16 +376,16 @@
     public int getAnimationStyle() {
         return mAnimationStyle;
     }
-    
+
     /**
-     * Set the flag on popup to ignore cheek press eventt; by default this flag
+     * Set the flag on popup to ignore cheek press event; by default this flag
      * is set to false
      * which means the pop wont ignore cheek press dispatch events.
-     * 
+     *
      * <p>If the popup is showing, calling this method will take effect only
      * the next time the popup is shown or through a manual call to one of
      * the {@link #update()} methods.</p>
-     * 
+     *
      * @see #update()
      */
     public void setIgnoreCheekPress() {
@@ -443,6 +446,19 @@
         if (mWindowManager == null && mContentView != null) {
             mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         }
+
+        // Setting the default for attachedInDecor based on SDK version here
+        // instead of in the constructor since we might not have the context
+        // object in the constructor. We only want to set default here if the
+        // app hasn't already set the attachedInDecor.
+        if (mContext != null && !mAttachedInDecorSet) {
+            // Attach popup window in decor frame of parent window by default for
+            // {@link Build.VERSION_CODES.LOLLIPOP_MR1} or greater. Keep current
+            // behavior of not attaching to decor frame for older SDKs.
+            setAttachedInDecor(mContext.getApplicationInfo().targetSdkVersion
+                    >= Build.VERSION_CODES.LOLLIPOP_MR1);
+        }
+
     }
 
     /**
@@ -452,7 +468,7 @@
     public void setTouchInterceptor(OnTouchListener l) {
         mTouchInterceptor = l;
     }
-    
+
     /**
      * <p>Indicate whether the popup window can grab the focus.</p>
      *
@@ -702,6 +718,36 @@
     }
 
     /**
+     * <p>Indicates whether the popup window will be attached in the decor frame of its parent
+     * window.
+     *
+     * @return true if the window will be attached to the decor frame of its parent window.
+     *
+     * @see #setAttachedInDecor(boolean)
+     * @see WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR
+     */
+    public boolean isAttachedInDecor() {
+        return mAttachedInDecor;
+    }
+
+    /**
+     * <p>This will attach the popup window to the decor frame of the parent window to avoid
+     * overlaping with screen decorations like the navigation bar. Overrides the default behavior of
+     * the flag {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR}.
+     *
+     * <p>By default the flag is set on SDK version {@link Build.VERSION_CODES#LOLLIPOP_MR1} or
+     * greater and cleared on lesser SDK versions.
+     *
+     * @param enabled true if the popup should be attached to the decor frame of its parent window.
+     *
+     * @see WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR
+     */
+    public void setAttachedInDecor(boolean enabled) {
+        mAttachedInDecor = enabled;
+        mAttachedInDecorSet = true;
+    }
+
+    /**
      * Allows the popup window to force the flag
      * {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}, overriding default behavior.
      * This will cause the popup to inset its content to account for system windows overlaying
@@ -1140,9 +1186,12 @@
         if (mNotTouchModal) {
             curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
         }
+        if (mAttachedInDecor) {
+          curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
+        }
         return curFlags;
     }
-    
+
     private int computeAnimationResource() {
         if (mAnimationStyle == -1) {
             if (mIsDropdown) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5cdee53..0917b32 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8518,6 +8518,7 @@
             } return false;
             case AccessibilityNodeInfo.ACTION_SET_SELECTION: {
                 if (isFocused() && canSelectText()) {
+                    ensureIterableTextForAccessibilitySelectable();
                     CharSequence text = getIterableTextForAccessibility();
                     if (text == null) {
                         return false;
@@ -8543,6 +8544,11 @@
                     }
                 }
             } return false;
+            case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
+            case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: {
+                ensureIterableTextForAccessibilitySelectable();
+                return super.performAccessibilityAction(action, arguments);
+            }
             default: {
                 return super.performAccessibilityAction(action, arguments);
             }
@@ -9032,10 +9038,13 @@
      */
     @Override
     public CharSequence getIterableTextForAccessibility() {
+        return mText;
+    }
+
+    private void ensureIterableTextForAccessibilitySelectable() {
         if (!(mText instanceof Spannable)) {
             setText(mText, BufferType.SPANNABLE);
         }
-        return mText;
     }
 
     /**
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 85cf67b..26e02f8 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -86,12 +86,12 @@
 
         switch (mode) {
             case MODE_CLOCK:
-                mDelegate = new TimePickerSpinnerDelegate(
+                mDelegate = new TimePickerClockDelegate(
                         this, context, attrs, defStyleAttr, defStyleRes);
                 break;
             case MODE_SPINNER:
             default:
-                mDelegate = new TimePickerClockDelegate(
+                mDelegate = new TimePickerSpinnerDelegate(
                         this, context, attrs, defStyleAttr, defStyleRes);
                 break;
         }
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 6dfea92..eca3048 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -17,365 +17,376 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.HapticFeedbackConstants;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
+
 import com.android.internal.R;
 
-import java.text.DateFormatSymbols;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Locale;
 
-import libcore.icu.LocaleData;
-
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
-
 /**
- * A delegate implementing the basic spinner-based TimePicker.
+ * A delegate implementing the radial clock-based TimePicker.
  */
-class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
+class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate implements
+        RadialTimePickerView.OnValueSelectedListener {
+
+    private static final String TAG = "TimePickerClockDelegate";
+
+    // Index used by RadialPickerLayout
+    private static final int HOUR_INDEX = 0;
+    private static final int MINUTE_INDEX = 1;
+
+    // NOT a real index for the purpose of what's showing.
+    private static final int AMPM_INDEX = 2;
+
+    // Also NOT a real index, just used for keyboard mode.
+    private static final int ENABLE_PICKER_INDEX = 3;
+
+    static final int AM = 0;
+    static final int PM = 1;
+
     private static final boolean DEFAULT_ENABLED_STATE = true;
+    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
+
     private static final int HOURS_IN_HALF_DAY = 12;
 
-    // state
+    private final View mHeaderView;
+    private final TextView mHourView;
+    private final TextView mMinuteView;
+    private final View mAmPmLayout;
+    private final CheckedTextView mAmLabel;
+    private final CheckedTextView mPmLabel;
+    private final RadialTimePickerView mRadialTimePickerView;
+    private final TextView mSeparatorView;
+
+    private final String mAmText;
+    private final String mPmText;
+
+    private final float mDisabledAlpha;
+
+    private boolean mAllowAutoAdvance;
+    private int mInitialHourOfDay;
+    private int mInitialMinute;
     private boolean mIs24HourView;
-    private boolean mIsAm;
 
-    // ui components
-    private final NumberPicker mHourSpinner;
-    private final NumberPicker mMinuteSpinner;
-    private final NumberPicker mAmPmSpinner;
-    private final EditText mHourSpinnerInput;
-    private final EditText mMinuteSpinnerInput;
-    private final EditText mAmPmSpinnerInput;
-    private final TextView mDivider;
+    // For hardware IME input.
+    private char mPlaceholderText;
+    private String mDoublePlaceholderText;
+    private String mDeletedKeyFormat;
+    private boolean mInKbMode;
+    private ArrayList<Integer> mTypedTimes = new ArrayList<Integer>();
+    private Node mLegalTimesTree;
+    private int mAmKeyCode;
+    private int mPmKeyCode;
 
-    // Note that the legacy implementation of the TimePicker is
-    // using a button for toggling between AM/PM while the new
-    // version uses a NumberPicker spinner. Therefore the code
-    // accommodates these two cases to be backwards compatible.
-    private final Button mAmPmButton;
+    // Accessibility strings.
+    private String mHourPickerDescription;
+    private String mSelectHours;
+    private String mMinutePickerDescription;
+    private String mSelectMinutes;
 
-    private final String[] mAmPmStrings;
+    // Most recent time announcement values for accessibility.
+    private CharSequence mLastAnnouncedText;
+    private boolean mLastAnnouncedIsHour;
 
-    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
     private Calendar mTempCalendar;
-    private boolean mHourWithTwoDigit;
-    private char mHourFormat;
 
     public TimePickerClockDelegate(TimePicker delegator, Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(delegator, context);
 
         // process style attributes
-        final TypedArray a = mContext.obtainStyledAttributes(
-                attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
-        final int layoutResourceId = a.getResourceId(
-                R.styleable.TimePicker_legacyLayout, R.layout.time_picker_legacy);
+        final TypedArray a = mContext.obtainStyledAttributes(attrs,
+                R.styleable.TimePicker, defStyleAttr, defStyleRes);
+        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        final Resources res = mContext.getResources();
+
+        mHourPickerDescription = res.getString(R.string.hour_picker_description);
+        mSelectHours = res.getString(R.string.select_hours);
+        mMinutePickerDescription = res.getString(R.string.minute_picker_description);
+        mSelectMinutes = res.getString(R.string.select_minutes);
+
+        String[] amPmStrings = TimePickerSpinnerDelegate.getAmPmStrings(context);
+        mAmText = amPmStrings[0];
+        mPmText = amPmStrings[1];
+
+        final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
+                R.layout.time_picker_holo);
+        final View mainView = inflater.inflate(layoutResourceId, delegator);
+
+        mHeaderView = mainView.findViewById(R.id.time_header);
+        mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
+
+        // Set up hour/minute labels.
+        mHourView = (TextView) mHeaderView.findViewById(R.id.hours);
+        mHourView.setOnClickListener(mClickListener);
+        mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator);
+        mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes);
+        mMinuteView.setOnClickListener(mClickListener);
+
+        final int headerTimeTextAppearance = a.getResourceId(
+                R.styleable.TimePicker_headerTimeTextAppearance, 0);
+        if (headerTimeTextAppearance != 0) {
+            mHourView.setTextAppearance(context, headerTimeTextAppearance);
+            mSeparatorView.setTextAppearance(context, headerTimeTextAppearance);
+            mMinuteView.setTextAppearance(context, headerTimeTextAppearance);
+        }
+
+        // TODO: This can be removed once we support themed color state lists.
+        final int headerSelectedTextColor = a.getColor(
+                R.styleable.TimePicker_headerSelectedTextColor,
+                res.getColor(R.color.timepicker_default_selector_color_material));
+        mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(),
+                R.attr.state_selected, headerSelectedTextColor));
+        mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(),
+                R.attr.state_selected, headerSelectedTextColor));
+
+        // Set up AM/PM labels.
+        mAmPmLayout = mHeaderView.findViewById(R.id.ampm_layout);
+        mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
+        mAmLabel.setText(amPmStrings[0]);
+        mAmLabel.setOnClickListener(mClickListener);
+        mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
+        mPmLabel.setText(amPmStrings[1]);
+        mPmLabel.setOnClickListener(mClickListener);
+
+        final int headerAmPmTextAppearance = a.getResourceId(
+                R.styleable.TimePicker_headerAmPmTextAppearance, 0);
+        if (headerAmPmTextAppearance != 0) {
+            mAmLabel.setTextAppearance(context, headerAmPmTextAppearance);
+            mPmLabel.setTextAppearance(context, headerAmPmTextAppearance);
+        }
+
         a.recycle();
 
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
-        inflater.inflate(layoutResourceId, mDelegator, true);
+        // Pull disabled alpha from theme.
+        final TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
+        mDisabledAlpha = outValue.getFloat();
 
-        // hour
-        mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour);
-        mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
-            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
-                updateInputState();
-                if (!is24HourView()) {
-                    if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) ||
-                            (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
-                        mIsAm = !mIsAm;
-                        updateAmPmControl();
-                    }
-                }
-                onTimeChanged();
-            }
-        });
-        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
-        mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(
+                R.id.radial_picker);
 
-        // divider (only for the new widget style)
-        mDivider = (TextView) mDelegator.findViewById(R.id.divider);
-        if (mDivider != null) {
-            setDividerText();
+        setupListeners();
+
+        mAllowAutoAdvance = true;
+
+        // Set up for keyboard mode.
+        mDoublePlaceholderText = res.getString(R.string.time_placeholder);
+        mDeletedKeyFormat = res.getString(R.string.deleted_key);
+        mPlaceholderText = mDoublePlaceholderText.charAt(0);
+        mAmKeyCode = mPmKeyCode = -1;
+        generateLegalTimesTree();
+
+        // Initialize with current time
+        final Calendar calendar = Calendar.getInstance(mCurrentLocale);
+        final int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
+        final int currentMinute = calendar.get(Calendar.MINUTE);
+        initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
+    }
+
+    private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) {
+        mInitialHourOfDay = hourOfDay;
+        mInitialMinute = minute;
+        mIs24HourView = is24HourView;
+        mInKbMode = false;
+        updateUI(index);
+    }
+
+    private void setupListeners() {
+        mHeaderView.setOnKeyListener(mKeyListener);
+        mHeaderView.setOnFocusChangeListener(mFocusListener);
+        mHeaderView.setFocusable(true);
+
+        mRadialTimePickerView.setOnValueSelectedListener(this);
+    }
+
+    private void updateUI(int index) {
+        // Update RadialPicker values
+        updateRadialPicker(index);
+        // Enable or disable the AM/PM view.
+        updateHeaderAmPm();
+        // Update Hour and Minutes
+        updateHeaderHour(mInitialHourOfDay, false);
+        // Update time separator
+        updateHeaderSeparator();
+        // Update Minutes
+        updateHeaderMinute(mInitialMinute, false);
+        // Invalidate everything
+        mDelegator.invalidate();
+    }
+
+    private void updateRadialPicker(int index) {
+        mRadialTimePickerView.initialize(mInitialHourOfDay, mInitialMinute, mIs24HourView);
+        setCurrentItemShowing(index, false, true);
+    }
+
+    private int computeMaxWidthOfNumbers(int max) {
+        TextView tempView = new TextView(mContext);
+        tempView.setTextAppearance(mContext, R.style.TextAppearance_Material_TimePicker_TimeLabel);
+        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        tempView.setLayoutParams(lp);
+        int maxWidth = 0;
+        for (int minutes = 0; minutes < max; minutes++) {
+            final String text = String.format("%02d", minutes);
+            tempView.setText(text);
+            tempView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+            maxWidth = Math.max(maxWidth, tempView.getMeasuredWidth());
         }
+        return maxWidth;
+    }
 
-        // minute
-        mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute);
-        mMinuteSpinner.setMinValue(0);
-        mMinuteSpinner.setMaxValue(59);
-        mMinuteSpinner.setOnLongPressUpdateInterval(100);
-        mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
-        mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
-            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
-                updateInputState();
-                int minValue = mMinuteSpinner.getMinValue();
-                int maxValue = mMinuteSpinner.getMaxValue();
-                if (oldVal == maxValue && newVal == minValue) {
-                    int newHour = mHourSpinner.getValue() + 1;
-                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) {
-                        mIsAm = !mIsAm;
-                        updateAmPmControl();
-                    }
-                    mHourSpinner.setValue(newHour);
-                } else if (oldVal == minValue && newVal == maxValue) {
-                    int newHour = mHourSpinner.getValue() - 1;
-                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) {
-                        mIsAm = !mIsAm;
-                        updateAmPmControl();
-                    }
-                    mHourSpinner.setValue(newHour);
-                }
-                onTimeChanged();
-            }
-        });
-        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
-        mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
-
-        // Get the localized am/pm strings and use them in the spinner.
-        mAmPmStrings = getAmPmStrings(context);
-
-        // am/pm
-        final View amPmView = mDelegator.findViewById(R.id.amPm);
-        if (amPmView instanceof Button) {
-            mAmPmSpinner = null;
-            mAmPmSpinnerInput = null;
-            mAmPmButton = (Button) amPmView;
-            mAmPmButton.setOnClickListener(new View.OnClickListener() {
-                public void onClick(View button) {
-                    button.requestFocus();
-                    mIsAm = !mIsAm;
-                    updateAmPmControl();
-                    onTimeChanged();
-                }
-            });
+    private void updateHeaderAmPm() {
+        if (mIs24HourView) {
+            mAmPmLayout.setVisibility(View.GONE);
         } else {
-            mAmPmButton = null;
-            mAmPmSpinner = (NumberPicker) amPmView;
-            mAmPmSpinner.setMinValue(0);
-            mAmPmSpinner.setMaxValue(1);
-            mAmPmSpinner.setDisplayedValues(mAmPmStrings);
-            mAmPmSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
-                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
-                    updateInputState();
-                    picker.requestFocus();
-                    mIsAm = !mIsAm;
-                    updateAmPmControl();
-                    onTimeChanged();
-                }
-            });
-            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
-            mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
-        }
-
-        if (isAmPmAtStart()) {
-            // Move the am/pm view to the beginning
-            ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout);
-            amPmParent.removeView(amPmView);
-            amPmParent.addView(amPmView, 0);
-            // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme
-            // for example and not for Holo Theme)
-            ViewGroup.MarginLayoutParams lp =
-                    (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams();
-            final int startMargin = lp.getMarginStart();
-            final int endMargin = lp.getMarginEnd();
-            if (startMargin != endMargin) {
-                lp.setMarginStart(endMargin);
-                lp.setMarginEnd(startMargin);
+            final String bestDateTimePattern = DateFormat.getBestDateTimePattern(
+                    mCurrentLocale, "hm");
+            boolean amPmOnLeft = bestDateTimePattern.startsWith("a");
+            if (TextUtils.getLayoutDirectionFromLocale(mCurrentLocale) ==
+                    View.LAYOUT_DIRECTION_RTL) {
+                amPmOnLeft = !amPmOnLeft;
             }
-        }
 
-        getHourFormatData();
+            final ViewGroup.MarginLayoutParams params =
+                    (ViewGroup.MarginLayoutParams) mAmPmLayout.getLayoutParams();
 
-        // update controls to initial state
-        updateHourControl();
-        updateMinuteControl();
-        updateAmPmControl();
-
-        // set to current time
-        setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
-        setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
-
-        if (!isEnabled()) {
-            setEnabled(false);
-        }
-
-        // set the content descriptions
-        setContentDescriptions();
-
-        // If not explicitly specified this view is important for accessibility.
-        if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-    }
-
-    private void getHourFormatData() {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                (mIs24HourView) ? "Hm" : "hm");
-        final int lengthPattern = bestDateTimePattern.length();
-        mHourWithTwoDigit = false;
-        char hourFormat = '\0';
-        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
-        // the hour format that we found.
-        for (int i = 0; i < lengthPattern; i++) {
-            final char c = bestDateTimePattern.charAt(i);
-            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
-                mHourFormat = c;
-                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
-                    mHourWithTwoDigit = true;
-                }
-                break;
+            if (amPmOnLeft) {
+                params.leftMargin = 0;
+                params.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */);
+            } else {
+                params.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */);
+                params.rightMargin = 0;
             }
+
+            mAmPmLayout.setLayoutParams(params);
+            mAmPmLayout.setVisibility(View.VISIBLE);
+
+            updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM);
         }
     }
 
-    private boolean isAmPmAtStart() {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                "hm" /* skeleton */);
-
-        return bestDateTimePattern.startsWith("a");
-    }
-
     /**
-     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
-     *
-     * See http://unicode.org/cldr/trac/browser/trunk/common/main
-     *
-     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
-     * separator as the character which is just after the hour marker in the returned pattern.
+     * Set the current hour.
      */
-    private void setDividerText() {
-        final String skeleton = (mIs24HourView) ? "Hm" : "hm";
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                skeleton);
-        final String separatorText;
-        int hourIndex = bestDateTimePattern.lastIndexOf('H');
-        if (hourIndex == -1) {
-            hourIndex = bestDateTimePattern.lastIndexOf('h');
-        }
-        if (hourIndex == -1) {
-            // Default case
-            separatorText = ":";
-        } else {
-            int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1);
-            if  (minuteIndex == -1) {
-                separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1));
-            } else {
-                separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex);
-            }
-        }
-        mDivider.setText(separatorText);
-    }
-
     @Override
     public void setCurrentHour(Integer currentHour) {
-        setCurrentHour(currentHour, true);
-    }
-
-    private void setCurrentHour(Integer currentHour, boolean notifyTimeChanged) {
-        // why was Integer used in the first place?
-        if (currentHour == null || currentHour == getCurrentHour()) {
+        if (mInitialHourOfDay == currentHour) {
             return;
         }
-        if (!is24HourView()) {
-            // convert [0,23] ordinal to wall clock display
-            if (currentHour >= HOURS_IN_HALF_DAY) {
-                mIsAm = false;
-                if (currentHour > HOURS_IN_HALF_DAY) {
-                    currentHour = currentHour - HOURS_IN_HALF_DAY;
-                }
-            } else {
-                mIsAm = true;
-                if (currentHour == 0) {
-                    currentHour = HOURS_IN_HALF_DAY;
-                }
-            }
-            updateAmPmControl();
-        }
-        mHourSpinner.setValue(currentHour);
-        if (notifyTimeChanged) {
-            onTimeChanged();
-        }
-    }
-
-    @Override
-    public Integer getCurrentHour() {
-        int currentHour = mHourSpinner.getValue();
-        if (is24HourView()) {
-            return currentHour;
-        } else if (mIsAm) {
-            return currentHour % HOURS_IN_HALF_DAY;
-        } else {
-            return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
-        }
-    }
-
-    @Override
-    public void setCurrentMinute(Integer currentMinute) {
-        if (currentMinute == getCurrentMinute()) {
-            return;
-        }
-        mMinuteSpinner.setValue(currentMinute);
+        mInitialHourOfDay = currentHour;
+        updateHeaderHour(currentHour, true);
+        updateHeaderAmPm();
+        mRadialTimePickerView.setCurrentHour(currentHour);
+        mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM);
+        mDelegator.invalidate();
         onTimeChanged();
     }
 
+    /**
+     * @return The current hour in the range (0-23).
+     */
     @Override
-    public Integer getCurrentMinute() {
-        return mMinuteSpinner.getValue();
+    public Integer getCurrentHour() {
+        int currentHour = mRadialTimePickerView.getCurrentHour();
+        if (mIs24HourView) {
+            return currentHour;
+        } else {
+            switch(mRadialTimePickerView.getAmOrPm()) {
+                case PM:
+                    return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
+                case AM:
+                default:
+                    return currentHour % HOURS_IN_HALF_DAY;
+            }
+        }
     }
 
+    /**
+     * Set the current minute (0-59).
+     */
     @Override
-    public void setIs24HourView(Boolean is24HourView) {
-        if (mIs24HourView == is24HourView) {
+    public void setCurrentMinute(Integer currentMinute) {
+        if (mInitialMinute == currentMinute) {
             return;
         }
-        // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!!
-        int currentHour = getCurrentHour();
-        // Order is important here.
-        mIs24HourView = is24HourView;
-        getHourFormatData();
-        updateHourControl();
-        // set value after spinner range is updated
-        setCurrentHour(currentHour, false);
-        updateMinuteControl();
-        updateAmPmControl();
+        mInitialMinute = currentMinute;
+        updateHeaderMinute(currentMinute, true);
+        mRadialTimePickerView.setCurrentMinute(currentMinute);
+        mDelegator.invalidate();
+        onTimeChanged();
     }
 
+    /**
+     * @return The current minute.
+     */
+    @Override
+    public Integer getCurrentMinute() {
+        return mRadialTimePickerView.getCurrentMinute();
+    }
+
+    /**
+     * Set whether in 24 hour or AM/PM mode.
+     *
+     * @param is24HourView True = 24 hour mode. False = AM/PM.
+     */
+    @Override
+    public void setIs24HourView(Boolean is24HourView) {
+        if (is24HourView == mIs24HourView) {
+            return;
+        }
+        mIs24HourView = is24HourView;
+        generateLegalTimesTree();
+        int hour = mRadialTimePickerView.getCurrentHour();
+        mInitialHourOfDay = hour;
+        updateHeaderHour(hour, false);
+        updateHeaderAmPm();
+        updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing());
+        mDelegator.invalidate();
+    }
+
+    /**
+     * @return true if this is in 24 hour view else false.
+     */
     @Override
     public boolean is24HourView() {
         return mIs24HourView;
     }
 
     @Override
-    public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener onTimeChangedListener) {
-        mOnTimeChangedListener = onTimeChangedListener;
+    public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener callback) {
+        mOnTimeChangedListener = callback;
     }
 
     @Override
     public void setEnabled(boolean enabled) {
-        mMinuteSpinner.setEnabled(enabled);
-        if (mDivider != null) {
-            mDivider.setEnabled(enabled);
-        }
-        mHourSpinner.setEnabled(enabled);
-        if (mAmPmSpinner != null) {
-            mAmPmSpinner.setEnabled(enabled);
-        } else {
-            mAmPmButton.setEnabled(enabled);
-        }
+        mHourView.setEnabled(enabled);
+        mMinuteView.setEnabled(enabled);
+        mAmLabel.setEnabled(enabled);
+        mPmLabel.setEnabled(enabled);
+        mRadialTimePickerView.setEnabled(enabled);
         mIsEnabled = enabled;
     }
 
@@ -386,24 +397,38 @@
 
     @Override
     public int getBaseline() {
-        return mHourSpinner.getBaseline();
+        // does not support baseline alignment
+        return -1;
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
-        setCurrentLocale(newConfig.locale);
+        updateUI(mRadialTimePickerView.getCurrentItemShowing());
     }
 
     @Override
     public Parcelable onSaveInstanceState(Parcelable superState) {
-        return new SavedState(superState, getCurrentHour(), getCurrentMinute());
+        return new SavedState(superState, getCurrentHour(), getCurrentMinute(),
+                is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing());
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
         SavedState ss = (SavedState) state;
-        setCurrentHour(ss.getHour());
-        setCurrentMinute(ss.getMinute());
+        setInKbMode(ss.inKbMode());
+        setTypedTimes(ss.getTypesTimes());
+        initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
+        mRadialTimePickerView.invalidate();
+        if (mInKbMode) {
+            tryStartingKbMode(-1);
+            mHourView.invalidate();
+        }
+    }
+
+    @Override
+    public void setCurrentLocale(Locale locale) {
+        super.setCurrentLocale(locale);
+        mTempCalendar = Calendar.getInstance(locale);
     }
 
     @Override
@@ -422,9 +447,9 @@
         }
         mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour());
         mTempCalendar.set(Calendar.MINUTE, getCurrentMinute());
-        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
+        String selectedDate = DateUtils.formatDateTime(mContext,
                 mTempCalendar.getTimeInMillis(), flags);
-        event.getText().add(selectedDateUtterance);
+        event.getText().add(selectedDate);
     }
 
     @Override
@@ -437,121 +462,48 @@
         info.setClassName(TimePicker.class.getName());
     }
 
-    private void updateInputState() {
-        // Make sure that if the user changes the value and the IME is active
-        // for one of the inputs if this widget, the IME is closed. If the user
-        // changed the value via the IME and there is a next input the IME will
-        // be shown, otherwise the user chose another means of changing the
-        // value and having the IME up makes no sense.
-        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
-        if (inputMethodManager != null) {
-            if (inputMethodManager.isActive(mHourSpinnerInput)) {
-                mHourSpinnerInput.clearFocus();
-                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-            } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) {
-                mMinuteSpinnerInput.clearFocus();
-                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-            } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) {
-                mAmPmSpinnerInput.clearFocus();
-                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-            }
-        }
-    }
-
-    private void updateAmPmControl() {
-        if (is24HourView()) {
-            if (mAmPmSpinner != null) {
-                mAmPmSpinner.setVisibility(View.GONE);
-            } else {
-                mAmPmButton.setVisibility(View.GONE);
-            }
-        } else {
-            int index = mIsAm ? Calendar.AM : Calendar.PM;
-            if (mAmPmSpinner != null) {
-                mAmPmSpinner.setValue(index);
-                mAmPmSpinner.setVisibility(View.VISIBLE);
-            } else {
-                mAmPmButton.setText(mAmPmStrings[index]);
-                mAmPmButton.setVisibility(View.VISIBLE);
-            }
-        }
-        mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+    /**
+     * Set whether in keyboard mode or not.
+     *
+     * @param inKbMode True means in keyboard mode.
+     */
+    private void setInKbMode(boolean inKbMode) {
+        mInKbMode = inKbMode;
     }
 
     /**
-     * Sets the current locale.
-     *
-     * @param locale The current locale.
+     * @return true if in keyboard mode
      */
-    @Override
-    public void setCurrentLocale(Locale locale) {
-        super.setCurrentLocale(locale);
-        mTempCalendar = Calendar.getInstance(locale);
+    private boolean inKbMode() {
+        return mInKbMode;
     }
 
+    private void setTypedTimes(ArrayList<Integer> typeTimes) {
+        mTypedTimes = typeTimes;
+    }
+
+    /**
+     * @return an array of typed times
+     */
+    private ArrayList<Integer> getTypedTimes() {
+        return mTypedTimes;
+    }
+
+    /**
+     * @return the index of the current item showing
+     */
+    private int getCurrentItemShowing() {
+        return mRadialTimePickerView.getCurrentItemShowing();
+    }
+
+    /**
+     * Propagate the time change
+     */
     private void onTimeChanged() {
         mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
         if (mOnTimeChangedListener != null) {
-            mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(),
-                    getCurrentMinute());
-        }
-    }
-
-    private void updateHourControl() {
-        if (is24HourView()) {
-            // 'k' means 1-24 hour
-            if (mHourFormat == 'k') {
-                mHourSpinner.setMinValue(1);
-                mHourSpinner.setMaxValue(24);
-            } else {
-                mHourSpinner.setMinValue(0);
-                mHourSpinner.setMaxValue(23);
-            }
-        } else {
-            // 'K' means 0-11 hour
-            if (mHourFormat == 'K') {
-                mHourSpinner.setMinValue(0);
-                mHourSpinner.setMaxValue(11);
-            } else {
-                mHourSpinner.setMinValue(1);
-                mHourSpinner.setMaxValue(12);
-            }
-        }
-        mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null);
-    }
-
-    private void updateMinuteControl() {
-        if (is24HourView()) {
-            mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
-        } else {
-            mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
-        }
-    }
-
-    private void setContentDescriptions() {
-        // Minute
-        trySetContentDescription(mMinuteSpinner, R.id.increment,
-                R.string.time_picker_increment_minute_button);
-        trySetContentDescription(mMinuteSpinner, R.id.decrement,
-                R.string.time_picker_decrement_minute_button);
-        // Hour
-        trySetContentDescription(mHourSpinner, R.id.increment,
-                R.string.time_picker_increment_hour_button);
-        trySetContentDescription(mHourSpinner, R.id.decrement,
-                R.string.time_picker_decrement_hour_button);
-        // AM/PM
-        if (mAmPmSpinner != null) {
-            trySetContentDescription(mAmPmSpinner, R.id.increment,
-                    R.string.time_picker_increment_set_pm_button);
-            trySetContentDescription(mAmPmSpinner, R.id.decrement,
-                    R.string.time_picker_decrement_set_am_button);
-        }
-    }
-
-    private void trySetContentDescription(View root, int viewId, int contDescResId) {
-        View target = root.findViewById(viewId);
-        if (target != null) {
-            target.setContentDescription(mContext.getString(contDescResId));
+            mOnTimeChangedListener.onTimeChanged(mDelegator,
+                    getCurrentHour(), getCurrentMinute());
         }
     }
 
@@ -559,19 +511,34 @@
      * Used to save / restore state of time picker
      */
     private static class SavedState extends View.BaseSavedState {
+
         private final int mHour;
         private final int mMinute;
+        private final boolean mIs24HourMode;
+        private final boolean mInKbMode;
+        private final ArrayList<Integer> mTypedTimes;
+        private final int mCurrentItemShowing;
 
-        private SavedState(Parcelable superState, int hour, int minute) {
+        private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
+                           boolean isKbMode, ArrayList<Integer> typedTimes,
+                           int currentItemShowing) {
             super(superState);
             mHour = hour;
             mMinute = minute;
+            mIs24HourMode = is24HourMode;
+            mInKbMode = isKbMode;
+            mTypedTimes = typedTimes;
+            mCurrentItemShowing = currentItemShowing;
         }
 
         private SavedState(Parcel in) {
             super(in);
             mHour = in.readInt();
             mMinute = in.readInt();
+            mIs24HourMode = (in.readInt() == 1);
+            mInKbMode = (in.readInt() == 1);
+            mTypedTimes = in.readArrayList(getClass().getClassLoader());
+            mCurrentItemShowing = in.readInt();
         }
 
         public int getHour() {
@@ -582,11 +549,31 @@
             return mMinute;
         }
 
+        public boolean is24HourMode() {
+            return mIs24HourMode;
+        }
+
+        public boolean inKbMode() {
+            return mInKbMode;
+        }
+
+        public ArrayList<Integer> getTypesTimes() {
+            return mTypedTimes;
+        }
+
+        public int getCurrentItemShowing() {
+            return mCurrentItemShowing;
+        }
+
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             super.writeToParcel(dest, flags);
             dest.writeInt(mHour);
             dest.writeInt(mMinute);
+            dest.writeInt(mIs24HourMode ? 1 : 0);
+            dest.writeInt(mInKbMode ? 1 : 0);
+            dest.writeList(mTypedTimes);
+            dest.writeInt(mCurrentItemShowing);
         }
 
         @SuppressWarnings({"unused", "hiding"})
@@ -601,11 +588,706 @@
         };
     }
 
-    public static String[] getAmPmStrings(Context context) {
-        String[] result = new String[2];
-        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
-        result[0] = d.amPm[0].length() > 2 ? d.narrowAm : d.amPm[0];
-        result[1] = d.amPm[1].length() > 2 ? d.narrowPm : d.amPm[1];
-        return result;
+    private void tryVibrate() {
+        mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
     }
+
+    private void updateAmPmLabelStates(int amOrPm) {
+        final boolean isAm = amOrPm == AM;
+        mAmLabel.setChecked(isAm);
+        mAmLabel.setAlpha(isAm ? 1 : mDisabledAlpha);
+
+        final boolean isPm = amOrPm == PM;
+        mPmLabel.setChecked(isPm);
+        mPmLabel.setAlpha(isPm ? 1 : mDisabledAlpha);
+    }
+
+    /**
+     * Called by the picker for updating the header display.
+     */
+    @Override
+    public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
+        if (pickerIndex == HOUR_INDEX) {
+            if (mAllowAutoAdvance && autoAdvance) {
+                updateHeaderHour(newValue, false);
+                setCurrentItemShowing(MINUTE_INDEX, true, false);
+                mRadialTimePickerView.announceForAccessibility(newValue + ". " + mSelectMinutes);
+            } else {
+                updateHeaderHour(newValue, true);
+                mRadialTimePickerView.setContentDescription(
+                        mHourPickerDescription + ": " + newValue);
+            }
+        } else if (pickerIndex == MINUTE_INDEX){
+            updateHeaderMinute(newValue, true);
+            mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + newValue);
+        } else if (pickerIndex == AMPM_INDEX) {
+            updateAmPmLabelStates(newValue);
+        } else if (pickerIndex == ENABLE_PICKER_INDEX) {
+            if (!isTypedTimeFullyLegal()) {
+                mTypedTimes.clear();
+            }
+            finishKbMode();
+        }
+    }
+
+    private void updateHeaderHour(int value, boolean announce) {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                (mIs24HourView) ? "Hm" : "hm");
+        final int lengthPattern = bestDateTimePattern.length();
+        boolean hourWithTwoDigit = false;
+        char hourFormat = '\0';
+        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
+        // the hour format that we found.
+        for (int i = 0; i < lengthPattern; i++) {
+            final char c = bestDateTimePattern.charAt(i);
+            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
+                hourFormat = c;
+                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
+                    hourWithTwoDigit = true;
+                }
+                break;
+            }
+        }
+        final String format;
+        if (hourWithTwoDigit) {
+            format = "%02d";
+        } else {
+            format = "%d";
+        }
+        if (mIs24HourView) {
+            // 'k' means 1-24 hour
+            if (hourFormat == 'k' && value == 0) {
+                value = 24;
+            }
+        } else {
+            // 'K' means 0-11 hour
+            value = modulo12(value, hourFormat == 'K');
+        }
+        CharSequence text = String.format(format, value);
+        mHourView.setText(text);
+        if (announce) {
+            tryAnnounceForAccessibility(text, true);
+        }
+    }
+
+    private void tryAnnounceForAccessibility(CharSequence text, boolean isHour) {
+        if (mLastAnnouncedIsHour != isHour || !text.equals(mLastAnnouncedText)) {
+            // TODO: Find a better solution, potentially live regions?
+            mDelegator.announceForAccessibility(text);
+            mLastAnnouncedText = text;
+            mLastAnnouncedIsHour = isHour;
+        }
+    }
+
+    private static int modulo12(int n, boolean startWithZero) {
+        int value = n % 12;
+        if (value == 0 && !startWithZero) {
+            value = 12;
+        }
+        return value;
+    }
+
+    /**
+     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
+     *
+     * See http://unicode.org/cldr/trac/browser/trunk/common/main
+     *
+     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
+     * separator as the character which is just after the hour marker in the returned pattern.
+     */
+    private void updateHeaderSeparator() {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                (mIs24HourView) ? "Hm" : "hm");
+        final String separatorText;
+        // See http://www.unicode.org/reports/tr35/tr35-dates.html for hour formats
+        final char[] hourFormats = {'H', 'h', 'K', 'k'};
+        int hIndex = lastIndexOfAny(bestDateTimePattern, hourFormats);
+        if (hIndex == -1) {
+            // Default case
+            separatorText = ":";
+        } else {
+            separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1));
+        }
+        mSeparatorView.setText(separatorText);
+    }
+
+    static private int lastIndexOfAny(String str, char[] any) {
+        final int lengthAny = any.length;
+        if (lengthAny > 0) {
+            for (int i = str.length() - 1; i >= 0; i--) {
+                char c = str.charAt(i);
+                for (int j = 0; j < lengthAny; j++) {
+                    if (c == any[j]) {
+                        return i;
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
+    private void updateHeaderMinute(int value, boolean announceForAccessibility) {
+        if (value == 60) {
+            value = 0;
+        }
+        final CharSequence text = String.format(mCurrentLocale, "%02d", value);
+        mMinuteView.setText(text);
+        if (announceForAccessibility) {
+            tryAnnounceForAccessibility(text, false);
+        }
+    }
+
+    /**
+     * Show either Hours or Minutes.
+     */
+    private void setCurrentItemShowing(int index, boolean animateCircle, boolean announce) {
+        mRadialTimePickerView.setCurrentItemShowing(index, animateCircle);
+
+        if (index == HOUR_INDEX) {
+            int hours = mRadialTimePickerView.getCurrentHour();
+            if (!mIs24HourView) {
+                hours = hours % 12;
+            }
+            mRadialTimePickerView.setContentDescription(mHourPickerDescription + ": " + hours);
+            if (announce) {
+                mRadialTimePickerView.announceForAccessibility(mSelectHours);
+            }
+        } else {
+            int minutes = mRadialTimePickerView.getCurrentMinute();
+            mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + minutes);
+            if (announce) {
+                mRadialTimePickerView.announceForAccessibility(mSelectMinutes);
+            }
+        }
+
+        mHourView.setSelected(index == HOUR_INDEX);
+        mMinuteView.setSelected(index == MINUTE_INDEX);
+    }
+
+    private void setAmOrPm(int amOrPm) {
+        updateAmPmLabelStates(amOrPm);
+        mRadialTimePickerView.setAmOrPm(amOrPm);
+    }
+
+    /**
+     * For keyboard mode, processes key events.
+     *
+     * @param keyCode the pressed key.
+     *
+     * @return true if the key was successfully processed, false otherwise.
+     */
+    private boolean processKeyUp(int keyCode) {
+        if (keyCode == KeyEvent.KEYCODE_DEL) {
+            if (mInKbMode) {
+                if (!mTypedTimes.isEmpty()) {
+                    int deleted = deleteLastTypedKey();
+                    String deletedKeyStr;
+                    if (deleted == getAmOrPmKeyCode(AM)) {
+                        deletedKeyStr = mAmText;
+                    } else if (deleted == getAmOrPmKeyCode(PM)) {
+                        deletedKeyStr = mPmText;
+                    } else {
+                        deletedKeyStr = String.format("%d", getValFromKeyCode(deleted));
+                    }
+                    mRadialTimePickerView.announceForAccessibility(
+                            String.format(mDeletedKeyFormat, deletedKeyStr));
+                    updateDisplay(true);
+                }
+            }
+        } else if (keyCode == KeyEvent.KEYCODE_0 || keyCode == KeyEvent.KEYCODE_1
+                || keyCode == KeyEvent.KEYCODE_2 || keyCode == KeyEvent.KEYCODE_3
+                || keyCode == KeyEvent.KEYCODE_4 || keyCode == KeyEvent.KEYCODE_5
+                || keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7
+                || keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9
+                || (!mIs24HourView &&
+                (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) {
+            if (!mInKbMode) {
+                if (mRadialTimePickerView == null) {
+                    // Something's wrong, because time picker should definitely not be null.
+                    Log.e(TAG, "Unable to initiate keyboard mode, TimePicker was null.");
+                    return true;
+                }
+                mTypedTimes.clear();
+                tryStartingKbMode(keyCode);
+                return true;
+            }
+            // We're already in keyboard mode.
+            if (addKeyIfLegal(keyCode)) {
+                updateDisplay(false);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Try to start keyboard mode with the specified key.
+     *
+     * @param keyCode The key to use as the first press. Keyboard mode will not be started if the
+     * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting
+     * key.
+     */
+    private void tryStartingKbMode(int keyCode) {
+        if (keyCode == -1 || addKeyIfLegal(keyCode)) {
+            mInKbMode = true;
+            onValidationChanged(false);
+            updateDisplay(false);
+            mRadialTimePickerView.setInputEnabled(false);
+        }
+    }
+
+    private boolean addKeyIfLegal(int keyCode) {
+        // If we're in 24hour mode, we'll need to check if the input is full. If in AM/PM mode,
+        // we'll need to see if AM/PM have been typed.
+        if ((mIs24HourView && mTypedTimes.size() == 4) ||
+                (!mIs24HourView && isTypedTimeFullyLegal())) {
+            return false;
+        }
+
+        mTypedTimes.add(keyCode);
+        if (!isTypedTimeLegalSoFar()) {
+            deleteLastTypedKey();
+            return false;
+        }
+
+        int val = getValFromKeyCode(keyCode);
+        mRadialTimePickerView.announceForAccessibility(String.format("%d", val));
+        // Automatically fill in 0's if AM or PM was legally entered.
+        if (isTypedTimeFullyLegal()) {
+            if (!mIs24HourView && mTypedTimes.size() <= 3) {
+                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
+                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
+            }
+            onValidationChanged(true);
+        }
+
+        return true;
+    }
+
+    /**
+     * Traverse the tree to see if the keys that have been typed so far are legal as is,
+     * or may become legal as more keys are typed (excluding backspace).
+     */
+    private boolean isTypedTimeLegalSoFar() {
+        Node node = mLegalTimesTree;
+        for (int keyCode : mTypedTimes) {
+            node = node.canReach(keyCode);
+            if (node == null) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Check if the time that has been typed so far is completely legal, as is.
+     */
+    private boolean isTypedTimeFullyLegal() {
+        if (mIs24HourView) {
+            // For 24-hour mode, the time is legal if the hours and minutes are each legal. Note:
+            // getEnteredTime() will ONLY call isTypedTimeFullyLegal() when NOT in 24hour mode.
+            int[] values = getEnteredTime(null);
+            return (values[0] >= 0 && values[1] >= 0 && values[1] < 60);
+        } else {
+            // For AM/PM mode, the time is legal if it contains an AM or PM, as those can only be
+            // legally added at specific times based on the tree's algorithm.
+            return (mTypedTimes.contains(getAmOrPmKeyCode(AM)) ||
+                    mTypedTimes.contains(getAmOrPmKeyCode(PM)));
+        }
+    }
+
+    private int deleteLastTypedKey() {
+        int deleted = mTypedTimes.remove(mTypedTimes.size() - 1);
+        if (!isTypedTimeFullyLegal()) {
+            onValidationChanged(false);
+        }
+        return deleted;
+    }
+
+    /**
+     * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time.
+     */
+    private void finishKbMode() {
+        mInKbMode = false;
+        if (!mTypedTimes.isEmpty()) {
+            int values[] = getEnteredTime(null);
+            mRadialTimePickerView.setCurrentHour(values[0]);
+            mRadialTimePickerView.setCurrentMinute(values[1]);
+            if (!mIs24HourView) {
+                mRadialTimePickerView.setAmOrPm(values[2]);
+            }
+            mTypedTimes.clear();
+        }
+        updateDisplay(false);
+        mRadialTimePickerView.setInputEnabled(true);
+    }
+
+    /**
+     * Update the hours, minutes, and AM/PM displays with the typed times. If the typedTimes is
+     * empty, either show an empty display (filled with the placeholder text), or update from the
+     * timepicker's values.
+     *
+     * @param allowEmptyDisplay if true, then if the typedTimes is empty, use the placeholder text.
+     * Otherwise, revert to the timepicker's values.
+     */
+    private void updateDisplay(boolean allowEmptyDisplay) {
+        if (!allowEmptyDisplay && mTypedTimes.isEmpty()) {
+            int hour = mRadialTimePickerView.getCurrentHour();
+            int minute = mRadialTimePickerView.getCurrentMinute();
+            updateHeaderHour(hour, false);
+            updateHeaderMinute(minute, false);
+            if (!mIs24HourView) {
+                updateAmPmLabelStates(hour < 12 ? AM : PM);
+            }
+            setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true);
+            onValidationChanged(true);
+        } else {
+            boolean[] enteredZeros = {false, false};
+            int[] values = getEnteredTime(enteredZeros);
+            String hourFormat = enteredZeros[0] ? "%02d" : "%2d";
+            String minuteFormat = (enteredZeros[1]) ? "%02d" : "%2d";
+            String hourStr = (values[0] == -1) ? mDoublePlaceholderText :
+                    String.format(hourFormat, values[0]).replace(' ', mPlaceholderText);
+            String minuteStr = (values[1] == -1) ? mDoublePlaceholderText :
+                    String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
+            mHourView.setText(hourStr);
+            mHourView.setSelected(false);
+            mMinuteView.setText(minuteStr);
+            mMinuteView.setSelected(false);
+            if (!mIs24HourView) {
+                updateAmPmLabelStates(values[2]);
+            }
+        }
+    }
+
+    private int getValFromKeyCode(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_0:
+                return 0;
+            case KeyEvent.KEYCODE_1:
+                return 1;
+            case KeyEvent.KEYCODE_2:
+                return 2;
+            case KeyEvent.KEYCODE_3:
+                return 3;
+            case KeyEvent.KEYCODE_4:
+                return 4;
+            case KeyEvent.KEYCODE_5:
+                return 5;
+            case KeyEvent.KEYCODE_6:
+                return 6;
+            case KeyEvent.KEYCODE_7:
+                return 7;
+            case KeyEvent.KEYCODE_8:
+                return 8;
+            case KeyEvent.KEYCODE_9:
+                return 9;
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * Get the currently-entered time, as integer values of the hours and minutes typed.
+     *
+     * @param enteredZeros A size-2 boolean array, which the caller should initialize, and which
+     * may then be used for the caller to know whether zeros had been explicitly entered as either
+     * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's.
+     *
+     * @return A size-3 int array. The first value will be the hours, the second value will be the
+     * minutes, and the third will be either AM or PM.
+     */
+    private int[] getEnteredTime(boolean[] enteredZeros) {
+        int amOrPm = -1;
+        int startIndex = 1;
+        if (!mIs24HourView && isTypedTimeFullyLegal()) {
+            int keyCode = mTypedTimes.get(mTypedTimes.size() - 1);
+            if (keyCode == getAmOrPmKeyCode(AM)) {
+                amOrPm = AM;
+            } else if (keyCode == getAmOrPmKeyCode(PM)){
+                amOrPm = PM;
+            }
+            startIndex = 2;
+        }
+        int minute = -1;
+        int hour = -1;
+        for (int i = startIndex; i <= mTypedTimes.size(); i++) {
+            int val = getValFromKeyCode(mTypedTimes.get(mTypedTimes.size() - i));
+            if (i == startIndex) {
+                minute = val;
+            } else if (i == startIndex+1) {
+                minute += 10 * val;
+                if (enteredZeros != null && val == 0) {
+                    enteredZeros[1] = true;
+                }
+            } else if (i == startIndex+2) {
+                hour = val;
+            } else if (i == startIndex+3) {
+                hour += 10 * val;
+                if (enteredZeros != null && val == 0) {
+                    enteredZeros[0] = true;
+                }
+            }
+        }
+
+        return new int[] { hour, minute, amOrPm };
+    }
+
+    /**
+     * Get the keycode value for AM and PM in the current language.
+     */
+    private int getAmOrPmKeyCode(int amOrPm) {
+        // Cache the codes.
+        if (mAmKeyCode == -1 || mPmKeyCode == -1) {
+            // Find the first character in the AM/PM text that is unique.
+            KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+            char amChar;
+            char pmChar;
+            for (int i = 0; i < Math.max(mAmText.length(), mPmText.length()); i++) {
+                amChar = mAmText.toLowerCase(mCurrentLocale).charAt(i);
+                pmChar = mPmText.toLowerCase(mCurrentLocale).charAt(i);
+                if (amChar != pmChar) {
+                    KeyEvent[] events = kcm.getEvents(new char[]{amChar, pmChar});
+                    // There should be 4 events: a down and up for both AM and PM.
+                    if (events != null && events.length == 4) {
+                        mAmKeyCode = events[0].getKeyCode();
+                        mPmKeyCode = events[2].getKeyCode();
+                    } else {
+                        Log.e(TAG, "Unable to find keycodes for AM and PM.");
+                    }
+                    break;
+                }
+            }
+        }
+        if (amOrPm == AM) {
+            return mAmKeyCode;
+        } else if (amOrPm == PM) {
+            return mPmKeyCode;
+        }
+
+        return -1;
+    }
+
+    /**
+     * Create a tree for deciding what keys can legally be typed.
+     */
+    private void generateLegalTimesTree() {
+        // Create a quick cache of numbers to their keycodes.
+        final int k0 = KeyEvent.KEYCODE_0;
+        final int k1 = KeyEvent.KEYCODE_1;
+        final int k2 = KeyEvent.KEYCODE_2;
+        final int k3 = KeyEvent.KEYCODE_3;
+        final int k4 = KeyEvent.KEYCODE_4;
+        final int k5 = KeyEvent.KEYCODE_5;
+        final int k6 = KeyEvent.KEYCODE_6;
+        final int k7 = KeyEvent.KEYCODE_7;
+        final int k8 = KeyEvent.KEYCODE_8;
+        final int k9 = KeyEvent.KEYCODE_9;
+
+        // The root of the tree doesn't contain any numbers.
+        mLegalTimesTree = new Node();
+        if (mIs24HourView) {
+            // We'll be re-using these nodes, so we'll save them.
+            Node minuteFirstDigit = new Node(k0, k1, k2, k3, k4, k5);
+            Node minuteSecondDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
+            // The first digit must be followed by the second digit.
+            minuteFirstDigit.addChild(minuteSecondDigit);
+
+            // The first digit may be 0-1.
+            Node firstDigit = new Node(k0, k1);
+            mLegalTimesTree.addChild(firstDigit);
+
+            // When the first digit is 0-1, the second digit may be 0-5.
+            Node secondDigit = new Node(k0, k1, k2, k3, k4, k5);
+            firstDigit.addChild(secondDigit);
+            // We may now be followed by the first minute digit. E.g. 00:09, 15:58.
+            secondDigit.addChild(minuteFirstDigit);
+
+            // When the first digit is 0-1, and the second digit is 0-5, the third digit may be 6-9.
+            Node thirdDigit = new Node(k6, k7, k8, k9);
+            // The time must now be finished. E.g. 0:55, 1:08.
+            secondDigit.addChild(thirdDigit);
+
+            // When the first digit is 0-1, the second digit may be 6-9.
+            secondDigit = new Node(k6, k7, k8, k9);
+            firstDigit.addChild(secondDigit);
+            // We must now be followed by the first minute digit. E.g. 06:50, 18:20.
+            secondDigit.addChild(minuteFirstDigit);
+
+            // The first digit may be 2.
+            firstDigit = new Node(k2);
+            mLegalTimesTree.addChild(firstDigit);
+
+            // When the first digit is 2, the second digit may be 0-3.
+            secondDigit = new Node(k0, k1, k2, k3);
+            firstDigit.addChild(secondDigit);
+            // We must now be followed by the first minute digit. E.g. 20:50, 23:09.
+            secondDigit.addChild(minuteFirstDigit);
+
+            // When the first digit is 2, the second digit may be 4-5.
+            secondDigit = new Node(k4, k5);
+            firstDigit.addChild(secondDigit);
+            // We must now be followd by the last minute digit. E.g. 2:40, 2:53.
+            secondDigit.addChild(minuteSecondDigit);
+
+            // The first digit may be 3-9.
+            firstDigit = new Node(k3, k4, k5, k6, k7, k8, k9);
+            mLegalTimesTree.addChild(firstDigit);
+            // We must now be followed by the first minute digit. E.g. 3:57, 8:12.
+            firstDigit.addChild(minuteFirstDigit);
+        } else {
+            // We'll need to use the AM/PM node a lot.
+            // Set up AM and PM to respond to "a" and "p".
+            Node ampm = new Node(getAmOrPmKeyCode(AM), getAmOrPmKeyCode(PM));
+
+            // The first hour digit may be 1.
+            Node firstDigit = new Node(k1);
+            mLegalTimesTree.addChild(firstDigit);
+            // We'll allow quick input of on-the-hour times. E.g. 1pm.
+            firstDigit.addChild(ampm);
+
+            // When the first digit is 1, the second digit may be 0-2.
+            Node secondDigit = new Node(k0, k1, k2);
+            firstDigit.addChild(secondDigit);
+            // Also for quick input of on-the-hour times. E.g. 10pm, 12am.
+            secondDigit.addChild(ampm);
+
+            // When the first digit is 1, and the second digit is 0-2, the third digit may be 0-5.
+            Node thirdDigit = new Node(k0, k1, k2, k3, k4, k5);
+            secondDigit.addChild(thirdDigit);
+            // The time may be finished now. E.g. 1:02pm, 1:25am.
+            thirdDigit.addChild(ampm);
+
+            // When the first digit is 1, the second digit is 0-2, and the third digit is 0-5,
+            // the fourth digit may be 0-9.
+            Node fourthDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
+            thirdDigit.addChild(fourthDigit);
+            // The time must be finished now. E.g. 10:49am, 12:40pm.
+            fourthDigit.addChild(ampm);
+
+            // When the first digit is 1, and the second digit is 0-2, the third digit may be 6-9.
+            thirdDigit = new Node(k6, k7, k8, k9);
+            secondDigit.addChild(thirdDigit);
+            // The time must be finished now. E.g. 1:08am, 1:26pm.
+            thirdDigit.addChild(ampm);
+
+            // When the first digit is 1, the second digit may be 3-5.
+            secondDigit = new Node(k3, k4, k5);
+            firstDigit.addChild(secondDigit);
+
+            // When the first digit is 1, and the second digit is 3-5, the third digit may be 0-9.
+            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
+            secondDigit.addChild(thirdDigit);
+            // The time must be finished now. E.g. 1:39am, 1:50pm.
+            thirdDigit.addChild(ampm);
+
+            // The hour digit may be 2-9.
+            firstDigit = new Node(k2, k3, k4, k5, k6, k7, k8, k9);
+            mLegalTimesTree.addChild(firstDigit);
+            // We'll allow quick input of on-the-hour-times. E.g. 2am, 5pm.
+            firstDigit.addChild(ampm);
+
+            // When the first digit is 2-9, the second digit may be 0-5.
+            secondDigit = new Node(k0, k1, k2, k3, k4, k5);
+            firstDigit.addChild(secondDigit);
+
+            // When the first digit is 2-9, and the second digit is 0-5, the third digit may be 0-9.
+            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
+            secondDigit.addChild(thirdDigit);
+            // The time must be finished now. E.g. 2:57am, 9:30pm.
+            thirdDigit.addChild(ampm);
+        }
+    }
+
+    /**
+     * Simple node class to be used for traversal to check for legal times.
+     * mLegalKeys represents the keys that can be typed to get to the node.
+     * mChildren are the children that can be reached from this node.
+     */
+    private class Node {
+        private int[] mLegalKeys;
+        private ArrayList<Node> mChildren;
+
+        public Node(int... legalKeys) {
+            mLegalKeys = legalKeys;
+            mChildren = new ArrayList<Node>();
+        }
+
+        public void addChild(Node child) {
+            mChildren.add(child);
+        }
+
+        public boolean containsKey(int key) {
+            for (int i = 0; i < mLegalKeys.length; i++) {
+                if (mLegalKeys[i] == key) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public Node canReach(int key) {
+            if (mChildren == null) {
+                return null;
+            }
+            for (Node child : mChildren) {
+                if (child.containsKey(key)) {
+                    return child;
+                }
+            }
+            return null;
+        }
+    }
+
+    private final View.OnClickListener mClickListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+
+            final int amOrPm;
+            switch (v.getId()) {
+                case R.id.am_label:
+                    setAmOrPm(AM);
+                    break;
+                case R.id.pm_label:
+                    setAmOrPm(PM);
+                    break;
+                case R.id.hours:
+                    setCurrentItemShowing(HOUR_INDEX, true, true);
+                    break;
+                case R.id.minutes:
+                    setCurrentItemShowing(MINUTE_INDEX, true, true);
+                    break;
+                default:
+                    // Failed to handle this click, don't vibrate.
+                    return;
+            }
+
+            tryVibrate();
+        }
+    };
+
+    private final View.OnKeyListener mKeyListener = new View.OnKeyListener() {
+        @Override
+        public boolean onKey(View v, int keyCode, KeyEvent event) {
+            if (event.getAction() == KeyEvent.ACTION_UP) {
+                return processKeyUp(keyCode);
+            }
+            return false;
+        }
+    };
+
+    private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() {
+        @Override
+        public void onFocusChange(View v, boolean hasFocus) {
+            if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) {
+                finishKbMode();
+
+                if (mOnTimeChangedListener != null) {
+                    mOnTimeChangedListener.onTimeChanged(mDelegator,
+                            mRadialTimePickerView.getCurrentHour(),
+                            mRadialTimePickerView.getCurrentMinute());
+                }
+            }
+        }
+    };
 }
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index d9c4114..e162f4a 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -17,376 +17,365 @@
 package android.widget;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.HapticFeedbackConstants;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 import com.android.internal.R;
 
-import java.util.ArrayList;
+import java.text.DateFormatSymbols;
 import java.util.Calendar;
 import java.util.Locale;
 
+import libcore.icu.LocaleData;
+
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+
 /**
- * A delegate implementing the radial clock-based TimePicker.
+ * A delegate implementing the basic spinner-based TimePicker.
  */
-class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate implements
-        RadialTimePickerView.OnValueSelectedListener {
-
-    private static final String TAG = "TimePickerDelegate";
-
-    // Index used by RadialPickerLayout
-    private static final int HOUR_INDEX = 0;
-    private static final int MINUTE_INDEX = 1;
-
-    // NOT a real index for the purpose of what's showing.
-    private static final int AMPM_INDEX = 2;
-
-    // Also NOT a real index, just used for keyboard mode.
-    private static final int ENABLE_PICKER_INDEX = 3;
-
-    static final int AM = 0;
-    static final int PM = 1;
-
+class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
     private static final boolean DEFAULT_ENABLED_STATE = true;
-    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
-
     private static final int HOURS_IN_HALF_DAY = 12;
 
-    private final View mHeaderView;
-    private final TextView mHourView;
-    private final TextView mMinuteView;
-    private final View mAmPmLayout;
-    private final CheckedTextView mAmLabel;
-    private final CheckedTextView mPmLabel;
-    private final RadialTimePickerView mRadialTimePickerView;
-    private final TextView mSeparatorView;
-
-    private final String mAmText;
-    private final String mPmText;
-
-    private final float mDisabledAlpha;
-
-    private boolean mAllowAutoAdvance;
-    private int mInitialHourOfDay;
-    private int mInitialMinute;
+    // state
     private boolean mIs24HourView;
+    private boolean mIsAm;
 
-    // For hardware IME input.
-    private char mPlaceholderText;
-    private String mDoublePlaceholderText;
-    private String mDeletedKeyFormat;
-    private boolean mInKbMode;
-    private ArrayList<Integer> mTypedTimes = new ArrayList<Integer>();
-    private Node mLegalTimesTree;
-    private int mAmKeyCode;
-    private int mPmKeyCode;
+    // ui components
+    private final NumberPicker mHourSpinner;
+    private final NumberPicker mMinuteSpinner;
+    private final NumberPicker mAmPmSpinner;
+    private final EditText mHourSpinnerInput;
+    private final EditText mMinuteSpinnerInput;
+    private final EditText mAmPmSpinnerInput;
+    private final TextView mDivider;
 
-    // Accessibility strings.
-    private String mHourPickerDescription;
-    private String mSelectHours;
-    private String mMinutePickerDescription;
-    private String mSelectMinutes;
+    // Note that the legacy implementation of the TimePicker is
+    // using a button for toggling between AM/PM while the new
+    // version uses a NumberPicker spinner. Therefore the code
+    // accommodates these two cases to be backwards compatible.
+    private final Button mAmPmButton;
 
-    // Most recent time announcement values for accessibility.
-    private CharSequence mLastAnnouncedText;
-    private boolean mLastAnnouncedIsHour;
+    private final String[] mAmPmStrings;
 
+    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
     private Calendar mTempCalendar;
+    private boolean mHourWithTwoDigit;
+    private char mHourFormat;
 
     public TimePickerSpinnerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(delegator, context);
 
         // process style attributes
-        final TypedArray a = mContext.obtainStyledAttributes(attrs,
-                R.styleable.TimePicker, defStyleAttr, defStyleRes);
-        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        final Resources res = mContext.getResources();
-
-        mHourPickerDescription = res.getString(R.string.hour_picker_description);
-        mSelectHours = res.getString(R.string.select_hours);
-        mMinutePickerDescription = res.getString(R.string.minute_picker_description);
-        mSelectMinutes = res.getString(R.string.select_minutes);
-
-        String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(context);
-        mAmText = amPmStrings[0];
-        mPmText = amPmStrings[1];
-
-        final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
-                R.layout.time_picker_holo);
-        final View mainView = inflater.inflate(layoutResourceId, delegator);
-
-        mHeaderView = mainView.findViewById(R.id.time_header);
-        mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
-
-        // Set up hour/minute labels.
-        mHourView = (TextView) mHeaderView.findViewById(R.id.hours);
-        mHourView.setOnClickListener(mClickListener);
-        mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator);
-        mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes);
-        mMinuteView.setOnClickListener(mClickListener);
-
-        final int headerTimeTextAppearance = a.getResourceId(
-                R.styleable.TimePicker_headerTimeTextAppearance, 0);
-        if (headerTimeTextAppearance != 0) {
-            mHourView.setTextAppearance(context, headerTimeTextAppearance);
-            mSeparatorView.setTextAppearance(context, headerTimeTextAppearance);
-            mMinuteView.setTextAppearance(context, headerTimeTextAppearance);
-        }
-
-        // TODO: This can be removed once we support themed color state lists.
-        final int headerSelectedTextColor = a.getColor(
-                R.styleable.TimePicker_headerSelectedTextColor,
-                res.getColor(R.color.timepicker_default_selector_color_material));
-        mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(),
-                R.attr.state_selected, headerSelectedTextColor));
-        mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(),
-                R.attr.state_selected, headerSelectedTextColor));
-
-        // Set up AM/PM labels.
-        mAmPmLayout = mHeaderView.findViewById(R.id.ampm_layout);
-        mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
-        mAmLabel.setText(amPmStrings[0]);
-        mAmLabel.setOnClickListener(mClickListener);
-        mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
-        mPmLabel.setText(amPmStrings[1]);
-        mPmLabel.setOnClickListener(mClickListener);
-
-        final int headerAmPmTextAppearance = a.getResourceId(
-                R.styleable.TimePicker_headerAmPmTextAppearance, 0);
-        if (headerAmPmTextAppearance != 0) {
-            mAmLabel.setTextAppearance(context, headerAmPmTextAppearance);
-            mPmLabel.setTextAppearance(context, headerAmPmTextAppearance);
-        }
-
+        final TypedArray a = mContext.obtainStyledAttributes(
+                attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
+        final int layoutResourceId = a.getResourceId(
+                R.styleable.TimePicker_legacyLayout, R.layout.time_picker_legacy);
         a.recycle();
 
-        // Pull disabled alpha from theme.
-        final TypedValue outValue = new TypedValue();
-        context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
-        mDisabledAlpha = outValue.getFloat();
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        inflater.inflate(layoutResourceId, mDelegator, true);
 
-        mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(
-                R.id.radial_picker);
+        // hour
+        mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour);
+        mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
+            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
+                updateInputState();
+                if (!is24HourView()) {
+                    if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) ||
+                            (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
+                    }
+                }
+                onTimeChanged();
+            }
+        });
+        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
+        mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
-        setupListeners();
-
-        mAllowAutoAdvance = true;
-
-        // Set up for keyboard mode.
-        mDoublePlaceholderText = res.getString(R.string.time_placeholder);
-        mDeletedKeyFormat = res.getString(R.string.deleted_key);
-        mPlaceholderText = mDoublePlaceholderText.charAt(0);
-        mAmKeyCode = mPmKeyCode = -1;
-        generateLegalTimesTree();
-
-        // Initialize with current time
-        final Calendar calendar = Calendar.getInstance(mCurrentLocale);
-        final int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
-        final int currentMinute = calendar.get(Calendar.MINUTE);
-        initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
-    }
-
-    private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) {
-        mInitialHourOfDay = hourOfDay;
-        mInitialMinute = minute;
-        mIs24HourView = is24HourView;
-        mInKbMode = false;
-        updateUI(index);
-    }
-
-    private void setupListeners() {
-        mHeaderView.setOnKeyListener(mKeyListener);
-        mHeaderView.setOnFocusChangeListener(mFocusListener);
-        mHeaderView.setFocusable(true);
-
-        mRadialTimePickerView.setOnValueSelectedListener(this);
-    }
-
-    private void updateUI(int index) {
-        // Update RadialPicker values
-        updateRadialPicker(index);
-        // Enable or disable the AM/PM view.
-        updateHeaderAmPm();
-        // Update Hour and Minutes
-        updateHeaderHour(mInitialHourOfDay, false);
-        // Update time separator
-        updateHeaderSeparator();
-        // Update Minutes
-        updateHeaderMinute(mInitialMinute, false);
-        // Invalidate everything
-        mDelegator.invalidate();
-    }
-
-    private void updateRadialPicker(int index) {
-        mRadialTimePickerView.initialize(mInitialHourOfDay, mInitialMinute, mIs24HourView);
-        setCurrentItemShowing(index, false, true);
-    }
-
-    private int computeMaxWidthOfNumbers(int max) {
-        TextView tempView = new TextView(mContext);
-        tempView.setTextAppearance(mContext, R.style.TextAppearance_Material_TimePicker_TimeLabel);
-        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
-        tempView.setLayoutParams(lp);
-        int maxWidth = 0;
-        for (int minutes = 0; minutes < max; minutes++) {
-            final String text = String.format("%02d", minutes);
-            tempView.setText(text);
-            tempView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-            maxWidth = Math.max(maxWidth, tempView.getMeasuredWidth());
+        // divider (only for the new widget style)
+        mDivider = (TextView) mDelegator.findViewById(R.id.divider);
+        if (mDivider != null) {
+            setDividerText();
         }
-        return maxWidth;
-    }
 
-    private void updateHeaderAmPm() {
-        if (mIs24HourView) {
-            mAmPmLayout.setVisibility(View.GONE);
+        // minute
+        mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute);
+        mMinuteSpinner.setMinValue(0);
+        mMinuteSpinner.setMaxValue(59);
+        mMinuteSpinner.setOnLongPressUpdateInterval(100);
+        mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
+        mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
+            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
+                updateInputState();
+                int minValue = mMinuteSpinner.getMinValue();
+                int maxValue = mMinuteSpinner.getMaxValue();
+                if (oldVal == maxValue && newVal == minValue) {
+                    int newHour = mHourSpinner.getValue() + 1;
+                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
+                    }
+                    mHourSpinner.setValue(newHour);
+                } else if (oldVal == minValue && newVal == maxValue) {
+                    int newHour = mHourSpinner.getValue() - 1;
+                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) {
+                        mIsAm = !mIsAm;
+                        updateAmPmControl();
+                    }
+                    mHourSpinner.setValue(newHour);
+                }
+                onTimeChanged();
+            }
+        });
+        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
+        mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+
+        // Get the localized am/pm strings and use them in the spinner.
+        mAmPmStrings = getAmPmStrings(context);
+
+        // am/pm
+        final View amPmView = mDelegator.findViewById(R.id.amPm);
+        if (amPmView instanceof Button) {
+            mAmPmSpinner = null;
+            mAmPmSpinnerInput = null;
+            mAmPmButton = (Button) amPmView;
+            mAmPmButton.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View button) {
+                    button.requestFocus();
+                    mIsAm = !mIsAm;
+                    updateAmPmControl();
+                    onTimeChanged();
+                }
+            });
         } else {
-            final String bestDateTimePattern = DateFormat.getBestDateTimePattern(
-                    mCurrentLocale, "hm");
-            boolean amPmOnLeft = bestDateTimePattern.startsWith("a");
-            if (TextUtils.getLayoutDirectionFromLocale(mCurrentLocale) ==
-                    View.LAYOUT_DIRECTION_RTL) {
-                amPmOnLeft = !amPmOnLeft;
-            }
-
-            final ViewGroup.MarginLayoutParams params =
-                    (ViewGroup.MarginLayoutParams) mAmPmLayout.getLayoutParams();
-
-            if (amPmOnLeft) {
-                params.leftMargin = 0;
-                params.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */);
-            } else {
-                params.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */);
-                params.rightMargin = 0;
-            }
-
-            mAmPmLayout.setLayoutParams(params);
-            mAmPmLayout.setVisibility(View.VISIBLE);
-
-            updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM);
+            mAmPmButton = null;
+            mAmPmSpinner = (NumberPicker) amPmView;
+            mAmPmSpinner.setMinValue(0);
+            mAmPmSpinner.setMaxValue(1);
+            mAmPmSpinner.setDisplayedValues(mAmPmStrings);
+            mAmPmSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
+                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+                    updateInputState();
+                    picker.requestFocus();
+                    mIsAm = !mIsAm;
+                    updateAmPmControl();
+                    onTimeChanged();
+                }
+            });
+            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
+            mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
         }
+
+        if (isAmPmAtStart()) {
+            // Move the am/pm view to the beginning
+            ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout);
+            amPmParent.removeView(amPmView);
+            amPmParent.addView(amPmView, 0);
+            // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme
+            // for example and not for Holo Theme)
+            ViewGroup.MarginLayoutParams lp =
+                    (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams();
+            final int startMargin = lp.getMarginStart();
+            final int endMargin = lp.getMarginEnd();
+            if (startMargin != endMargin) {
+                lp.setMarginStart(endMargin);
+                lp.setMarginEnd(startMargin);
+            }
+        }
+
+        getHourFormatData();
+
+        // update controls to initial state
+        updateHourControl();
+        updateMinuteControl();
+        updateAmPmControl();
+
+        // set to current time
+        setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
+        setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
+
+        if (!isEnabled()) {
+            setEnabled(false);
+        }
+
+        // set the content descriptions
+        setContentDescriptions();
+
+        // If not explicitly specified this view is important for accessibility.
+        if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+    }
+
+    private void getHourFormatData() {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                (mIs24HourView) ? "Hm" : "hm");
+        final int lengthPattern = bestDateTimePattern.length();
+        mHourWithTwoDigit = false;
+        char hourFormat = '\0';
+        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
+        // the hour format that we found.
+        for (int i = 0; i < lengthPattern; i++) {
+            final char c = bestDateTimePattern.charAt(i);
+            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
+                mHourFormat = c;
+                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
+                    mHourWithTwoDigit = true;
+                }
+                break;
+            }
+        }
+    }
+
+    private boolean isAmPmAtStart() {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                "hm" /* skeleton */);
+
+        return bestDateTimePattern.startsWith("a");
     }
 
     /**
-     * Set the current hour.
+     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
+     *
+     * See http://unicode.org/cldr/trac/browser/trunk/common/main
+     *
+     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
+     * separator as the character which is just after the hour marker in the returned pattern.
      */
+    private void setDividerText() {
+        final String skeleton = (mIs24HourView) ? "Hm" : "hm";
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
+                skeleton);
+        final String separatorText;
+        int hourIndex = bestDateTimePattern.lastIndexOf('H');
+        if (hourIndex == -1) {
+            hourIndex = bestDateTimePattern.lastIndexOf('h');
+        }
+        if (hourIndex == -1) {
+            // Default case
+            separatorText = ":";
+        } else {
+            int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1);
+            if  (minuteIndex == -1) {
+                separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1));
+            } else {
+                separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex);
+            }
+        }
+        mDivider.setText(separatorText);
+    }
+
     @Override
     public void setCurrentHour(Integer currentHour) {
-        if (mInitialHourOfDay == currentHour) {
-            return;
-        }
-        mInitialHourOfDay = currentHour;
-        updateHeaderHour(currentHour, true);
-        updateHeaderAmPm();
-        mRadialTimePickerView.setCurrentHour(currentHour);
-        mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM);
-        mDelegator.invalidate();
-        onTimeChanged();
+        setCurrentHour(currentHour, true);
     }
 
-    /**
-     * @return The current hour in the range (0-23).
-     */
+    private void setCurrentHour(Integer currentHour, boolean notifyTimeChanged) {
+        // why was Integer used in the first place?
+        if (currentHour == null || currentHour == getCurrentHour()) {
+            return;
+        }
+        if (!is24HourView()) {
+            // convert [0,23] ordinal to wall clock display
+            if (currentHour >= HOURS_IN_HALF_DAY) {
+                mIsAm = false;
+                if (currentHour > HOURS_IN_HALF_DAY) {
+                    currentHour = currentHour - HOURS_IN_HALF_DAY;
+                }
+            } else {
+                mIsAm = true;
+                if (currentHour == 0) {
+                    currentHour = HOURS_IN_HALF_DAY;
+                }
+            }
+            updateAmPmControl();
+        }
+        mHourSpinner.setValue(currentHour);
+        if (notifyTimeChanged) {
+            onTimeChanged();
+        }
+    }
+
     @Override
     public Integer getCurrentHour() {
-        int currentHour = mRadialTimePickerView.getCurrentHour();
-        if (mIs24HourView) {
+        int currentHour = mHourSpinner.getValue();
+        if (is24HourView()) {
             return currentHour;
+        } else if (mIsAm) {
+            return currentHour % HOURS_IN_HALF_DAY;
         } else {
-            switch(mRadialTimePickerView.getAmOrPm()) {
-                case PM:
-                    return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
-                case AM:
-                default:
-                    return currentHour % HOURS_IN_HALF_DAY;
-            }
+            return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
         }
     }
 
-    /**
-     * Set the current minute (0-59).
-     */
     @Override
     public void setCurrentMinute(Integer currentMinute) {
-        if (mInitialMinute == currentMinute) {
+        if (currentMinute == getCurrentMinute()) {
             return;
         }
-        mInitialMinute = currentMinute;
-        updateHeaderMinute(currentMinute, true);
-        mRadialTimePickerView.setCurrentMinute(currentMinute);
-        mDelegator.invalidate();
+        mMinuteSpinner.setValue(currentMinute);
         onTimeChanged();
     }
 
-    /**
-     * @return The current minute.
-     */
     @Override
     public Integer getCurrentMinute() {
-        return mRadialTimePickerView.getCurrentMinute();
+        return mMinuteSpinner.getValue();
     }
 
-    /**
-     * Set whether in 24 hour or AM/PM mode.
-     *
-     * @param is24HourView True = 24 hour mode. False = AM/PM.
-     */
     @Override
     public void setIs24HourView(Boolean is24HourView) {
-        if (is24HourView == mIs24HourView) {
+        if (mIs24HourView == is24HourView) {
             return;
         }
+        // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!!
+        int currentHour = getCurrentHour();
+        // Order is important here.
         mIs24HourView = is24HourView;
-        generateLegalTimesTree();
-        int hour = mRadialTimePickerView.getCurrentHour();
-        mInitialHourOfDay = hour;
-        updateHeaderHour(hour, false);
-        updateHeaderAmPm();
-        updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing());
-        mDelegator.invalidate();
+        getHourFormatData();
+        updateHourControl();
+        // set value after spinner range is updated
+        setCurrentHour(currentHour, false);
+        updateMinuteControl();
+        updateAmPmControl();
     }
 
-    /**
-     * @return true if this is in 24 hour view else false.
-     */
     @Override
     public boolean is24HourView() {
         return mIs24HourView;
     }
 
     @Override
-    public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener callback) {
-        mOnTimeChangedListener = callback;
+    public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener onTimeChangedListener) {
+        mOnTimeChangedListener = onTimeChangedListener;
     }
 
     @Override
     public void setEnabled(boolean enabled) {
-        mHourView.setEnabled(enabled);
-        mMinuteView.setEnabled(enabled);
-        mAmLabel.setEnabled(enabled);
-        mPmLabel.setEnabled(enabled);
-        mRadialTimePickerView.setEnabled(enabled);
+        mMinuteSpinner.setEnabled(enabled);
+        if (mDivider != null) {
+            mDivider.setEnabled(enabled);
+        }
+        mHourSpinner.setEnabled(enabled);
+        if (mAmPmSpinner != null) {
+            mAmPmSpinner.setEnabled(enabled);
+        } else {
+            mAmPmButton.setEnabled(enabled);
+        }
         mIsEnabled = enabled;
     }
 
@@ -397,38 +386,24 @@
 
     @Override
     public int getBaseline() {
-        // does not support baseline alignment
-        return -1;
+        return mHourSpinner.getBaseline();
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
-        updateUI(mRadialTimePickerView.getCurrentItemShowing());
+        setCurrentLocale(newConfig.locale);
     }
 
     @Override
     public Parcelable onSaveInstanceState(Parcelable superState) {
-        return new SavedState(superState, getCurrentHour(), getCurrentMinute(),
-                is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing());
+        return new SavedState(superState, getCurrentHour(), getCurrentMinute());
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
         SavedState ss = (SavedState) state;
-        setInKbMode(ss.inKbMode());
-        setTypedTimes(ss.getTypesTimes());
-        initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
-        mRadialTimePickerView.invalidate();
-        if (mInKbMode) {
-            tryStartingKbMode(-1);
-            mHourView.invalidate();
-        }
-    }
-
-    @Override
-    public void setCurrentLocale(Locale locale) {
-        super.setCurrentLocale(locale);
-        mTempCalendar = Calendar.getInstance(locale);
+        setCurrentHour(ss.getHour());
+        setCurrentMinute(ss.getMinute());
     }
 
     @Override
@@ -447,9 +422,9 @@
         }
         mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour());
         mTempCalendar.set(Calendar.MINUTE, getCurrentMinute());
-        String selectedDate = DateUtils.formatDateTime(mContext,
+        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
                 mTempCalendar.getTimeInMillis(), flags);
-        event.getText().add(selectedDate);
+        event.getText().add(selectedDateUtterance);
     }
 
     @Override
@@ -462,48 +437,121 @@
         info.setClassName(TimePicker.class.getName());
     }
 
+    private void updateInputState() {
+        // Make sure that if the user changes the value and the IME is active
+        // for one of the inputs if this widget, the IME is closed. If the user
+        // changed the value via the IME and there is a next input the IME will
+        // be shown, otherwise the user chose another means of changing the
+        // value and having the IME up makes no sense.
+        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        if (inputMethodManager != null) {
+            if (inputMethodManager.isActive(mHourSpinnerInput)) {
+                mHourSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) {
+                mMinuteSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) {
+                mAmPmSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            }
+        }
+    }
+
+    private void updateAmPmControl() {
+        if (is24HourView()) {
+            if (mAmPmSpinner != null) {
+                mAmPmSpinner.setVisibility(View.GONE);
+            } else {
+                mAmPmButton.setVisibility(View.GONE);
+            }
+        } else {
+            int index = mIsAm ? Calendar.AM : Calendar.PM;
+            if (mAmPmSpinner != null) {
+                mAmPmSpinner.setValue(index);
+                mAmPmSpinner.setVisibility(View.VISIBLE);
+            } else {
+                mAmPmButton.setText(mAmPmStrings[index]);
+                mAmPmButton.setVisibility(View.VISIBLE);
+            }
+        }
+        mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+    }
+
     /**
-     * Set whether in keyboard mode or not.
+     * Sets the current locale.
      *
-     * @param inKbMode True means in keyboard mode.
+     * @param locale The current locale.
      */
-    private void setInKbMode(boolean inKbMode) {
-        mInKbMode = inKbMode;
+    @Override
+    public void setCurrentLocale(Locale locale) {
+        super.setCurrentLocale(locale);
+        mTempCalendar = Calendar.getInstance(locale);
     }
 
-    /**
-     * @return true if in keyboard mode
-     */
-    private boolean inKbMode() {
-        return mInKbMode;
-    }
-
-    private void setTypedTimes(ArrayList<Integer> typeTimes) {
-        mTypedTimes = typeTimes;
-    }
-
-    /**
-     * @return an array of typed times
-     */
-    private ArrayList<Integer> getTypedTimes() {
-        return mTypedTimes;
-    }
-
-    /**
-     * @return the index of the current item showing
-     */
-    private int getCurrentItemShowing() {
-        return mRadialTimePickerView.getCurrentItemShowing();
-    }
-
-    /**
-     * Propagate the time change
-     */
     private void onTimeChanged() {
         mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
         if (mOnTimeChangedListener != null) {
-            mOnTimeChangedListener.onTimeChanged(mDelegator,
-                    getCurrentHour(), getCurrentMinute());
+            mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(),
+                    getCurrentMinute());
+        }
+    }
+
+    private void updateHourControl() {
+        if (is24HourView()) {
+            // 'k' means 1-24 hour
+            if (mHourFormat == 'k') {
+                mHourSpinner.setMinValue(1);
+                mHourSpinner.setMaxValue(24);
+            } else {
+                mHourSpinner.setMinValue(0);
+                mHourSpinner.setMaxValue(23);
+            }
+        } else {
+            // 'K' means 0-11 hour
+            if (mHourFormat == 'K') {
+                mHourSpinner.setMinValue(0);
+                mHourSpinner.setMaxValue(11);
+            } else {
+                mHourSpinner.setMinValue(1);
+                mHourSpinner.setMaxValue(12);
+            }
+        }
+        mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null);
+    }
+
+    private void updateMinuteControl() {
+        if (is24HourView()) {
+            mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
+        } else {
+            mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        }
+    }
+
+    private void setContentDescriptions() {
+        // Minute
+        trySetContentDescription(mMinuteSpinner, R.id.increment,
+                R.string.time_picker_increment_minute_button);
+        trySetContentDescription(mMinuteSpinner, R.id.decrement,
+                R.string.time_picker_decrement_minute_button);
+        // Hour
+        trySetContentDescription(mHourSpinner, R.id.increment,
+                R.string.time_picker_increment_hour_button);
+        trySetContentDescription(mHourSpinner, R.id.decrement,
+                R.string.time_picker_decrement_hour_button);
+        // AM/PM
+        if (mAmPmSpinner != null) {
+            trySetContentDescription(mAmPmSpinner, R.id.increment,
+                    R.string.time_picker_increment_set_pm_button);
+            trySetContentDescription(mAmPmSpinner, R.id.decrement,
+                    R.string.time_picker_decrement_set_am_button);
+        }
+    }
+
+    private void trySetContentDescription(View root, int viewId, int contDescResId) {
+        View target = root.findViewById(viewId);
+        if (target != null) {
+            target.setContentDescription(mContext.getString(contDescResId));
         }
     }
 
@@ -511,34 +559,19 @@
      * Used to save / restore state of time picker
      */
     private static class SavedState extends View.BaseSavedState {
-
         private final int mHour;
         private final int mMinute;
-        private final boolean mIs24HourMode;
-        private final boolean mInKbMode;
-        private final ArrayList<Integer> mTypedTimes;
-        private final int mCurrentItemShowing;
 
-        private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
-                           boolean isKbMode, ArrayList<Integer> typedTimes,
-                           int currentItemShowing) {
+        private SavedState(Parcelable superState, int hour, int minute) {
             super(superState);
             mHour = hour;
             mMinute = minute;
-            mIs24HourMode = is24HourMode;
-            mInKbMode = isKbMode;
-            mTypedTimes = typedTimes;
-            mCurrentItemShowing = currentItemShowing;
         }
 
         private SavedState(Parcel in) {
             super(in);
             mHour = in.readInt();
             mMinute = in.readInt();
-            mIs24HourMode = (in.readInt() == 1);
-            mInKbMode = (in.readInt() == 1);
-            mTypedTimes = in.readArrayList(getClass().getClassLoader());
-            mCurrentItemShowing = in.readInt();
         }
 
         public int getHour() {
@@ -549,31 +582,11 @@
             return mMinute;
         }
 
-        public boolean is24HourMode() {
-            return mIs24HourMode;
-        }
-
-        public boolean inKbMode() {
-            return mInKbMode;
-        }
-
-        public ArrayList<Integer> getTypesTimes() {
-            return mTypedTimes;
-        }
-
-        public int getCurrentItemShowing() {
-            return mCurrentItemShowing;
-        }
-
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             super.writeToParcel(dest, flags);
             dest.writeInt(mHour);
             dest.writeInt(mMinute);
-            dest.writeInt(mIs24HourMode ? 1 : 0);
-            dest.writeInt(mInKbMode ? 1 : 0);
-            dest.writeList(mTypedTimes);
-            dest.writeInt(mCurrentItemShowing);
         }
 
         @SuppressWarnings({"unused", "hiding"})
@@ -588,706 +601,11 @@
         };
     }
 
-    private void tryVibrate() {
-        mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+    public static String[] getAmPmStrings(Context context) {
+        String[] result = new String[2];
+        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
+        result[0] = d.amPm[0].length() > 2 ? d.narrowAm : d.amPm[0];
+        result[1] = d.amPm[1].length() > 2 ? d.narrowPm : d.amPm[1];
+        return result;
     }
-
-    private void updateAmPmLabelStates(int amOrPm) {
-        final boolean isAm = amOrPm == AM;
-        mAmLabel.setChecked(isAm);
-        mAmLabel.setAlpha(isAm ? 1 : mDisabledAlpha);
-
-        final boolean isPm = amOrPm == PM;
-        mPmLabel.setChecked(isPm);
-        mPmLabel.setAlpha(isPm ? 1 : mDisabledAlpha);
-    }
-
-    /**
-     * Called by the picker for updating the header display.
-     */
-    @Override
-    public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
-        if (pickerIndex == HOUR_INDEX) {
-            if (mAllowAutoAdvance && autoAdvance) {
-                updateHeaderHour(newValue, false);
-                setCurrentItemShowing(MINUTE_INDEX, true, false);
-                mRadialTimePickerView.announceForAccessibility(newValue + ". " + mSelectMinutes);
-            } else {
-                updateHeaderHour(newValue, true);
-                mRadialTimePickerView.setContentDescription(
-                        mHourPickerDescription + ": " + newValue);
-            }
-        } else if (pickerIndex == MINUTE_INDEX){
-            updateHeaderMinute(newValue, true);
-            mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + newValue);
-        } else if (pickerIndex == AMPM_INDEX) {
-            updateAmPmLabelStates(newValue);
-        } else if (pickerIndex == ENABLE_PICKER_INDEX) {
-            if (!isTypedTimeFullyLegal()) {
-                mTypedTimes.clear();
-            }
-            finishKbMode();
-        }
-    }
-
-    private void updateHeaderHour(int value, boolean announce) {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                (mIs24HourView) ? "Hm" : "hm");
-        final int lengthPattern = bestDateTimePattern.length();
-        boolean hourWithTwoDigit = false;
-        char hourFormat = '\0';
-        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
-        // the hour format that we found.
-        for (int i = 0; i < lengthPattern; i++) {
-            final char c = bestDateTimePattern.charAt(i);
-            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
-                hourFormat = c;
-                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
-                    hourWithTwoDigit = true;
-                }
-                break;
-            }
-        }
-        final String format;
-        if (hourWithTwoDigit) {
-            format = "%02d";
-        } else {
-            format = "%d";
-        }
-        if (mIs24HourView) {
-            // 'k' means 1-24 hour
-            if (hourFormat == 'k' && value == 0) {
-                value = 24;
-            }
-        } else {
-            // 'K' means 0-11 hour
-            value = modulo12(value, hourFormat == 'K');
-        }
-        CharSequence text = String.format(format, value);
-        mHourView.setText(text);
-        if (announce) {
-            tryAnnounceForAccessibility(text, true);
-        }
-    }
-
-    private void tryAnnounceForAccessibility(CharSequence text, boolean isHour) {
-        if (mLastAnnouncedIsHour != isHour || !text.equals(mLastAnnouncedText)) {
-            // TODO: Find a better solution, potentially live regions?
-            mDelegator.announceForAccessibility(text);
-            mLastAnnouncedText = text;
-            mLastAnnouncedIsHour = isHour;
-        }
-    }
-
-    private static int modulo12(int n, boolean startWithZero) {
-        int value = n % 12;
-        if (value == 0 && !startWithZero) {
-            value = 12;
-        }
-        return value;
-    }
-
-    /**
-     * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":".
-     *
-     * See http://unicode.org/cldr/trac/browser/trunk/common/main
-     *
-     * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the
-     * separator as the character which is just after the hour marker in the returned pattern.
-     */
-    private void updateHeaderSeparator() {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                (mIs24HourView) ? "Hm" : "hm");
-        final String separatorText;
-        // See http://www.unicode.org/reports/tr35/tr35-dates.html for hour formats
-        final char[] hourFormats = {'H', 'h', 'K', 'k'};
-        int hIndex = lastIndexOfAny(bestDateTimePattern, hourFormats);
-        if (hIndex == -1) {
-            // Default case
-            separatorText = ":";
-        } else {
-            separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1));
-        }
-        mSeparatorView.setText(separatorText);
-    }
-
-    static private int lastIndexOfAny(String str, char[] any) {
-        final int lengthAny = any.length;
-        if (lengthAny > 0) {
-            for (int i = str.length() - 1; i >= 0; i--) {
-                char c = str.charAt(i);
-                for (int j = 0; j < lengthAny; j++) {
-                    if (c == any[j]) {
-                        return i;
-                    }
-                }
-            }
-        }
-        return -1;
-    }
-
-    private void updateHeaderMinute(int value, boolean announceForAccessibility) {
-        if (value == 60) {
-            value = 0;
-        }
-        final CharSequence text = String.format(mCurrentLocale, "%02d", value);
-        mMinuteView.setText(text);
-        if (announceForAccessibility) {
-            tryAnnounceForAccessibility(text, false);
-        }
-    }
-
-    /**
-     * Show either Hours or Minutes.
-     */
-    private void setCurrentItemShowing(int index, boolean animateCircle, boolean announce) {
-        mRadialTimePickerView.setCurrentItemShowing(index, animateCircle);
-
-        if (index == HOUR_INDEX) {
-            int hours = mRadialTimePickerView.getCurrentHour();
-            if (!mIs24HourView) {
-                hours = hours % 12;
-            }
-            mRadialTimePickerView.setContentDescription(mHourPickerDescription + ": " + hours);
-            if (announce) {
-                mRadialTimePickerView.announceForAccessibility(mSelectHours);
-            }
-        } else {
-            int minutes = mRadialTimePickerView.getCurrentMinute();
-            mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + minutes);
-            if (announce) {
-                mRadialTimePickerView.announceForAccessibility(mSelectMinutes);
-            }
-        }
-
-        mHourView.setSelected(index == HOUR_INDEX);
-        mMinuteView.setSelected(index == MINUTE_INDEX);
-    }
-
-    private void setAmOrPm(int amOrPm) {
-        updateAmPmLabelStates(amOrPm);
-        mRadialTimePickerView.setAmOrPm(amOrPm);
-    }
-
-    /**
-     * For keyboard mode, processes key events.
-     *
-     * @param keyCode the pressed key.
-     *
-     * @return true if the key was successfully processed, false otherwise.
-     */
-    private boolean processKeyUp(int keyCode) {
-        if (keyCode == KeyEvent.KEYCODE_DEL) {
-            if (mInKbMode) {
-                if (!mTypedTimes.isEmpty()) {
-                    int deleted = deleteLastTypedKey();
-                    String deletedKeyStr;
-                    if (deleted == getAmOrPmKeyCode(AM)) {
-                        deletedKeyStr = mAmText;
-                    } else if (deleted == getAmOrPmKeyCode(PM)) {
-                        deletedKeyStr = mPmText;
-                    } else {
-                        deletedKeyStr = String.format("%d", getValFromKeyCode(deleted));
-                    }
-                    mRadialTimePickerView.announceForAccessibility(
-                            String.format(mDeletedKeyFormat, deletedKeyStr));
-                    updateDisplay(true);
-                }
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_0 || keyCode == KeyEvent.KEYCODE_1
-                || keyCode == KeyEvent.KEYCODE_2 || keyCode == KeyEvent.KEYCODE_3
-                || keyCode == KeyEvent.KEYCODE_4 || keyCode == KeyEvent.KEYCODE_5
-                || keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7
-                || keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9
-                || (!mIs24HourView &&
-                (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) {
-            if (!mInKbMode) {
-                if (mRadialTimePickerView == null) {
-                    // Something's wrong, because time picker should definitely not be null.
-                    Log.e(TAG, "Unable to initiate keyboard mode, TimePicker was null.");
-                    return true;
-                }
-                mTypedTimes.clear();
-                tryStartingKbMode(keyCode);
-                return true;
-            }
-            // We're already in keyboard mode.
-            if (addKeyIfLegal(keyCode)) {
-                updateDisplay(false);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Try to start keyboard mode with the specified key.
-     *
-     * @param keyCode The key to use as the first press. Keyboard mode will not be started if the
-     * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting
-     * key.
-     */
-    private void tryStartingKbMode(int keyCode) {
-        if (keyCode == -1 || addKeyIfLegal(keyCode)) {
-            mInKbMode = true;
-            onValidationChanged(false);
-            updateDisplay(false);
-            mRadialTimePickerView.setInputEnabled(false);
-        }
-    }
-
-    private boolean addKeyIfLegal(int keyCode) {
-        // If we're in 24hour mode, we'll need to check if the input is full. If in AM/PM mode,
-        // we'll need to see if AM/PM have been typed.
-        if ((mIs24HourView && mTypedTimes.size() == 4) ||
-                (!mIs24HourView && isTypedTimeFullyLegal())) {
-            return false;
-        }
-
-        mTypedTimes.add(keyCode);
-        if (!isTypedTimeLegalSoFar()) {
-            deleteLastTypedKey();
-            return false;
-        }
-
-        int val = getValFromKeyCode(keyCode);
-        mRadialTimePickerView.announceForAccessibility(String.format("%d", val));
-        // Automatically fill in 0's if AM or PM was legally entered.
-        if (isTypedTimeFullyLegal()) {
-            if (!mIs24HourView && mTypedTimes.size() <= 3) {
-                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
-                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
-            }
-            onValidationChanged(true);
-        }
-
-        return true;
-    }
-
-    /**
-     * Traverse the tree to see if the keys that have been typed so far are legal as is,
-     * or may become legal as more keys are typed (excluding backspace).
-     */
-    private boolean isTypedTimeLegalSoFar() {
-        Node node = mLegalTimesTree;
-        for (int keyCode : mTypedTimes) {
-            node = node.canReach(keyCode);
-            if (node == null) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Check if the time that has been typed so far is completely legal, as is.
-     */
-    private boolean isTypedTimeFullyLegal() {
-        if (mIs24HourView) {
-            // For 24-hour mode, the time is legal if the hours and minutes are each legal. Note:
-            // getEnteredTime() will ONLY call isTypedTimeFullyLegal() when NOT in 24hour mode.
-            int[] values = getEnteredTime(null);
-            return (values[0] >= 0 && values[1] >= 0 && values[1] < 60);
-        } else {
-            // For AM/PM mode, the time is legal if it contains an AM or PM, as those can only be
-            // legally added at specific times based on the tree's algorithm.
-            return (mTypedTimes.contains(getAmOrPmKeyCode(AM)) ||
-                    mTypedTimes.contains(getAmOrPmKeyCode(PM)));
-        }
-    }
-
-    private int deleteLastTypedKey() {
-        int deleted = mTypedTimes.remove(mTypedTimes.size() - 1);
-        if (!isTypedTimeFullyLegal()) {
-            onValidationChanged(false);
-        }
-        return deleted;
-    }
-
-    /**
-     * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time.
-     */
-    private void finishKbMode() {
-        mInKbMode = false;
-        if (!mTypedTimes.isEmpty()) {
-            int values[] = getEnteredTime(null);
-            mRadialTimePickerView.setCurrentHour(values[0]);
-            mRadialTimePickerView.setCurrentMinute(values[1]);
-            if (!mIs24HourView) {
-                mRadialTimePickerView.setAmOrPm(values[2]);
-            }
-            mTypedTimes.clear();
-        }
-        updateDisplay(false);
-        mRadialTimePickerView.setInputEnabled(true);
-    }
-
-    /**
-     * Update the hours, minutes, and AM/PM displays with the typed times. If the typedTimes is
-     * empty, either show an empty display (filled with the placeholder text), or update from the
-     * timepicker's values.
-     *
-     * @param allowEmptyDisplay if true, then if the typedTimes is empty, use the placeholder text.
-     * Otherwise, revert to the timepicker's values.
-     */
-    private void updateDisplay(boolean allowEmptyDisplay) {
-        if (!allowEmptyDisplay && mTypedTimes.isEmpty()) {
-            int hour = mRadialTimePickerView.getCurrentHour();
-            int minute = mRadialTimePickerView.getCurrentMinute();
-            updateHeaderHour(hour, false);
-            updateHeaderMinute(minute, false);
-            if (!mIs24HourView) {
-                updateAmPmLabelStates(hour < 12 ? AM : PM);
-            }
-            setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true);
-            onValidationChanged(true);
-        } else {
-            boolean[] enteredZeros = {false, false};
-            int[] values = getEnteredTime(enteredZeros);
-            String hourFormat = enteredZeros[0] ? "%02d" : "%2d";
-            String minuteFormat = (enteredZeros[1]) ? "%02d" : "%2d";
-            String hourStr = (values[0] == -1) ? mDoublePlaceholderText :
-                    String.format(hourFormat, values[0]).replace(' ', mPlaceholderText);
-            String minuteStr = (values[1] == -1) ? mDoublePlaceholderText :
-                    String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
-            mHourView.setText(hourStr);
-            mHourView.setSelected(false);
-            mMinuteView.setText(minuteStr);
-            mMinuteView.setSelected(false);
-            if (!mIs24HourView) {
-                updateAmPmLabelStates(values[2]);
-            }
-        }
-    }
-
-    private int getValFromKeyCode(int keyCode) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_0:
-                return 0;
-            case KeyEvent.KEYCODE_1:
-                return 1;
-            case KeyEvent.KEYCODE_2:
-                return 2;
-            case KeyEvent.KEYCODE_3:
-                return 3;
-            case KeyEvent.KEYCODE_4:
-                return 4;
-            case KeyEvent.KEYCODE_5:
-                return 5;
-            case KeyEvent.KEYCODE_6:
-                return 6;
-            case KeyEvent.KEYCODE_7:
-                return 7;
-            case KeyEvent.KEYCODE_8:
-                return 8;
-            case KeyEvent.KEYCODE_9:
-                return 9;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * Get the currently-entered time, as integer values of the hours and minutes typed.
-     *
-     * @param enteredZeros A size-2 boolean array, which the caller should initialize, and which
-     * may then be used for the caller to know whether zeros had been explicitly entered as either
-     * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's.
-     *
-     * @return A size-3 int array. The first value will be the hours, the second value will be the
-     * minutes, and the third will be either AM or PM.
-     */
-    private int[] getEnteredTime(boolean[] enteredZeros) {
-        int amOrPm = -1;
-        int startIndex = 1;
-        if (!mIs24HourView && isTypedTimeFullyLegal()) {
-            int keyCode = mTypedTimes.get(mTypedTimes.size() - 1);
-            if (keyCode == getAmOrPmKeyCode(AM)) {
-                amOrPm = AM;
-            } else if (keyCode == getAmOrPmKeyCode(PM)){
-                amOrPm = PM;
-            }
-            startIndex = 2;
-        }
-        int minute = -1;
-        int hour = -1;
-        for (int i = startIndex; i <= mTypedTimes.size(); i++) {
-            int val = getValFromKeyCode(mTypedTimes.get(mTypedTimes.size() - i));
-            if (i == startIndex) {
-                minute = val;
-            } else if (i == startIndex+1) {
-                minute += 10 * val;
-                if (enteredZeros != null && val == 0) {
-                    enteredZeros[1] = true;
-                }
-            } else if (i == startIndex+2) {
-                hour = val;
-            } else if (i == startIndex+3) {
-                hour += 10 * val;
-                if (enteredZeros != null && val == 0) {
-                    enteredZeros[0] = true;
-                }
-            }
-        }
-
-        return new int[] { hour, minute, amOrPm };
-    }
-
-    /**
-     * Get the keycode value for AM and PM in the current language.
-     */
-    private int getAmOrPmKeyCode(int amOrPm) {
-        // Cache the codes.
-        if (mAmKeyCode == -1 || mPmKeyCode == -1) {
-            // Find the first character in the AM/PM text that is unique.
-            KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
-            char amChar;
-            char pmChar;
-            for (int i = 0; i < Math.max(mAmText.length(), mPmText.length()); i++) {
-                amChar = mAmText.toLowerCase(mCurrentLocale).charAt(i);
-                pmChar = mPmText.toLowerCase(mCurrentLocale).charAt(i);
-                if (amChar != pmChar) {
-                    KeyEvent[] events = kcm.getEvents(new char[]{amChar, pmChar});
-                    // There should be 4 events: a down and up for both AM and PM.
-                    if (events != null && events.length == 4) {
-                        mAmKeyCode = events[0].getKeyCode();
-                        mPmKeyCode = events[2].getKeyCode();
-                    } else {
-                        Log.e(TAG, "Unable to find keycodes for AM and PM.");
-                    }
-                    break;
-                }
-            }
-        }
-        if (amOrPm == AM) {
-            return mAmKeyCode;
-        } else if (amOrPm == PM) {
-            return mPmKeyCode;
-        }
-
-        return -1;
-    }
-
-    /**
-     * Create a tree for deciding what keys can legally be typed.
-     */
-    private void generateLegalTimesTree() {
-        // Create a quick cache of numbers to their keycodes.
-        final int k0 = KeyEvent.KEYCODE_0;
-        final int k1 = KeyEvent.KEYCODE_1;
-        final int k2 = KeyEvent.KEYCODE_2;
-        final int k3 = KeyEvent.KEYCODE_3;
-        final int k4 = KeyEvent.KEYCODE_4;
-        final int k5 = KeyEvent.KEYCODE_5;
-        final int k6 = KeyEvent.KEYCODE_6;
-        final int k7 = KeyEvent.KEYCODE_7;
-        final int k8 = KeyEvent.KEYCODE_8;
-        final int k9 = KeyEvent.KEYCODE_9;
-
-        // The root of the tree doesn't contain any numbers.
-        mLegalTimesTree = new Node();
-        if (mIs24HourView) {
-            // We'll be re-using these nodes, so we'll save them.
-            Node minuteFirstDigit = new Node(k0, k1, k2, k3, k4, k5);
-            Node minuteSecondDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            // The first digit must be followed by the second digit.
-            minuteFirstDigit.addChild(minuteSecondDigit);
-
-            // The first digit may be 0-1.
-            Node firstDigit = new Node(k0, k1);
-            mLegalTimesTree.addChild(firstDigit);
-
-            // When the first digit is 0-1, the second digit may be 0-5.
-            Node secondDigit = new Node(k0, k1, k2, k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-            // We may now be followed by the first minute digit. E.g. 00:09, 15:58.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // When the first digit is 0-1, and the second digit is 0-5, the third digit may be 6-9.
-            Node thirdDigit = new Node(k6, k7, k8, k9);
-            // The time must now be finished. E.g. 0:55, 1:08.
-            secondDigit.addChild(thirdDigit);
-
-            // When the first digit is 0-1, the second digit may be 6-9.
-            secondDigit = new Node(k6, k7, k8, k9);
-            firstDigit.addChild(secondDigit);
-            // We must now be followed by the first minute digit. E.g. 06:50, 18:20.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // The first digit may be 2.
-            firstDigit = new Node(k2);
-            mLegalTimesTree.addChild(firstDigit);
-
-            // When the first digit is 2, the second digit may be 0-3.
-            secondDigit = new Node(k0, k1, k2, k3);
-            firstDigit.addChild(secondDigit);
-            // We must now be followed by the first minute digit. E.g. 20:50, 23:09.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // When the first digit is 2, the second digit may be 4-5.
-            secondDigit = new Node(k4, k5);
-            firstDigit.addChild(secondDigit);
-            // We must now be followd by the last minute digit. E.g. 2:40, 2:53.
-            secondDigit.addChild(minuteSecondDigit);
-
-            // The first digit may be 3-9.
-            firstDigit = new Node(k3, k4, k5, k6, k7, k8, k9);
-            mLegalTimesTree.addChild(firstDigit);
-            // We must now be followed by the first minute digit. E.g. 3:57, 8:12.
-            firstDigit.addChild(minuteFirstDigit);
-        } else {
-            // We'll need to use the AM/PM node a lot.
-            // Set up AM and PM to respond to "a" and "p".
-            Node ampm = new Node(getAmOrPmKeyCode(AM), getAmOrPmKeyCode(PM));
-
-            // The first hour digit may be 1.
-            Node firstDigit = new Node(k1);
-            mLegalTimesTree.addChild(firstDigit);
-            // We'll allow quick input of on-the-hour times. E.g. 1pm.
-            firstDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit may be 0-2.
-            Node secondDigit = new Node(k0, k1, k2);
-            firstDigit.addChild(secondDigit);
-            // Also for quick input of on-the-hour times. E.g. 10pm, 12am.
-            secondDigit.addChild(ampm);
-
-            // When the first digit is 1, and the second digit is 0-2, the third digit may be 0-5.
-            Node thirdDigit = new Node(k0, k1, k2, k3, k4, k5);
-            secondDigit.addChild(thirdDigit);
-            // The time may be finished now. E.g. 1:02pm, 1:25am.
-            thirdDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit is 0-2, and the third digit is 0-5,
-            // the fourth digit may be 0-9.
-            Node fourthDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            thirdDigit.addChild(fourthDigit);
-            // The time must be finished now. E.g. 10:49am, 12:40pm.
-            fourthDigit.addChild(ampm);
-
-            // When the first digit is 1, and the second digit is 0-2, the third digit may be 6-9.
-            thirdDigit = new Node(k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 1:08am, 1:26pm.
-            thirdDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit may be 3-5.
-            secondDigit = new Node(k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-
-            // When the first digit is 1, and the second digit is 3-5, the third digit may be 0-9.
-            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 1:39am, 1:50pm.
-            thirdDigit.addChild(ampm);
-
-            // The hour digit may be 2-9.
-            firstDigit = new Node(k2, k3, k4, k5, k6, k7, k8, k9);
-            mLegalTimesTree.addChild(firstDigit);
-            // We'll allow quick input of on-the-hour-times. E.g. 2am, 5pm.
-            firstDigit.addChild(ampm);
-
-            // When the first digit is 2-9, the second digit may be 0-5.
-            secondDigit = new Node(k0, k1, k2, k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-
-            // When the first digit is 2-9, and the second digit is 0-5, the third digit may be 0-9.
-            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 2:57am, 9:30pm.
-            thirdDigit.addChild(ampm);
-        }
-    }
-
-    /**
-     * Simple node class to be used for traversal to check for legal times.
-     * mLegalKeys represents the keys that can be typed to get to the node.
-     * mChildren are the children that can be reached from this node.
-     */
-    private class Node {
-        private int[] mLegalKeys;
-        private ArrayList<Node> mChildren;
-
-        public Node(int... legalKeys) {
-            mLegalKeys = legalKeys;
-            mChildren = new ArrayList<Node>();
-        }
-
-        public void addChild(Node child) {
-            mChildren.add(child);
-        }
-
-        public boolean containsKey(int key) {
-            for (int i = 0; i < mLegalKeys.length; i++) {
-                if (mLegalKeys[i] == key) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public Node canReach(int key) {
-            if (mChildren == null) {
-                return null;
-            }
-            for (Node child : mChildren) {
-                if (child.containsKey(key)) {
-                    return child;
-                }
-            }
-            return null;
-        }
-    }
-
-    private final View.OnClickListener mClickListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-
-            final int amOrPm;
-            switch (v.getId()) {
-                case R.id.am_label:
-                    setAmOrPm(AM);
-                    break;
-                case R.id.pm_label:
-                    setAmOrPm(PM);
-                    break;
-                case R.id.hours:
-                    setCurrentItemShowing(HOUR_INDEX, true, true);
-                    break;
-                case R.id.minutes:
-                    setCurrentItemShowing(MINUTE_INDEX, true, true);
-                    break;
-                default:
-                    // Failed to handle this click, don't vibrate.
-                    return;
-            }
-
-            tryVibrate();
-        }
-    };
-
-    private final View.OnKeyListener mKeyListener = new View.OnKeyListener() {
-        @Override
-        public boolean onKey(View v, int keyCode, KeyEvent event) {
-            if (event.getAction() == KeyEvent.ACTION_UP) {
-                return processKeyUp(keyCode);
-            }
-            return false;
-        }
-    };
-
-    private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() {
-        @Override
-        public void onFocusChange(View v, boolean hasFocus) {
-            if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) {
-                finishKbMode();
-
-                if (mOnTimeChangedListener != null) {
-                    mOnTimeChangedListener.onTimeChanged(mDelegator,
-                            mRadialTimePickerView.getCurrentHour(),
-                            mRadialTimePickerView.getCurrentMinute());
-                }
-            }
-        }
-    };
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 91e5330..b9a85e5 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -19,8 +19,6 @@
 import android.animation.LayoutTransition;
 import android.app.ActionBar;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
@@ -29,9 +27,7 @@
 import android.text.Layout;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.CollapsibleActionView;
-import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -111,10 +107,10 @@
     private int mProgressBarPadding;
     private int mItemPadding;
 
-    private int mTitleStyleRes;
-    private int mSubtitleStyleRes;
-    private int mProgressStyle;
-    private int mIndeterminateProgressStyle;
+    private final int mTitleStyleRes;
+    private final int mSubtitleStyleRes;
+    private final int mProgressStyle;
+    private final int mIndeterminateProgressStyle;
 
     private boolean mUserTitle;
     private boolean mIncludeTabs;
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 97b1634..99b1bae 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -17,6 +17,7 @@
 package com.android.internal.widget;
 
 import android.animation.TimeInterpolator;
+import android.app.Activity;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -102,6 +103,13 @@
                 android.R.integer.config_shortAnimTime);
         mCancelInterpolator = new DecelerateInterpolator(1.5f);
         mDismissInterpolator = new AccelerateInterpolator(1.5f);
+        // SwipeDismissLayout assumes that the host Activity is translucent
+        // and temporarily disables translucency when it is fully visible.
+        // As soon as the user starts swiping, we will re-enable
+        // translucency.
+        if (context instanceof Activity) {
+            ((Activity) context).convertFromTranslucent();
+        }
     }
 
     public void setOnDismissedListener(OnDismissedListener listener) {
@@ -197,6 +205,9 @@
                 mLastX = ev.getRawX();
                 updateSwiping(ev);
                 if (mSwiping) {
+                    if (getContext() instanceof Activity) {
+                        ((Activity) getContext()).convertToTranslucent(null, null);
+                    }
                     setProgress(ev.getRawX() - mDownX);
                     break;
                 }
@@ -218,6 +229,9 @@
     }
 
     protected void cancel() {
+        if (getContext() instanceof Activity) {
+            ((Activity) getContext()).convertFromTranslucent();
+        }
         if (mProgressListener != null) {
             mProgressListener.onSwipeCancelled(this);
         }
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index e0abc24..a578b5d 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -315,7 +315,8 @@
     }
 
     SkBitmap decodingBitmap;
-    if (!decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode)) {
+    if (decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode)
+                != SkImageDecoder::kSuccess) {
         return nullObjectReturn("decoder->decode returned false");
     }
 
diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml
index 24e55b1..774732d 100644
--- a/core/res/res/values-mcc310-mnc120/config.xml
+++ b/core/res/res/values-mcc310-mnc120/config.xml
@@ -27,4 +27,8 @@
 
     <!-- Sprint need a 70 ms delay for 3way call -->
     <integer name="config_cdma_3waycall_flash_delay">70</integer>
+
+    <!-- If this value is true, The mms content-disposition field is supported correctly.
+         If false, Content-disposition fragments are ignored -->
+    <bool name="config_mms_content_disposition_support">false</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc160/config.xml b/core/res/res/values-mcc310-mnc160/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc200/config.xml b/core/res/res/values-mcc310-mnc200/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc200/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc210/config.xml b/core/res/res/values-mcc310-mnc210/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc210/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc220/config.xml b/core/res/res/values-mcc310-mnc220/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc220/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc230/config.xml b/core/res/res/values-mcc310-mnc230/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc230/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc240/config.xml b/core/res/res/values-mcc310-mnc240/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc240/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc250/config.xml b/core/res/res/values-mcc310-mnc250/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc250/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index 28cd695..6bfc3d1 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -25,8 +25,8 @@
     -->
     <integer name="config_mobile_mtu">1440</integer>
 
-    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+    <!-- Flag specifying whether VoLTE should be available for carrier: independent of
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
-    <bool name="config_carrier_volte_vt_available">true</bool>
+    <bool name="config_carrier_volte_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc270/config.xml b/core/res/res/values-mcc310-mnc270/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc270/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc300/config.xml b/core/res/res/values-mcc310-mnc300/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc300/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc310/config.xml b/core/res/res/values-mcc310-mnc310/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc310/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc490/config.xml b/core/res/res/values-mcc310-mnc490/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc490/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc530/config.xml b/core/res/res/values-mcc310-mnc530/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc530/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc580/config.xml b/core/res/res/values-mcc310-mnc580/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc580/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc590/config.xml b/core/res/res/values-mcc310-mnc590/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc590/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc640/config.xml b/core/res/res/values-mcc310-mnc640/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc640/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc660/config.xml b/core/res/res/values-mcc310-mnc660/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc660/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc800/config.xml b/core/res/res/values-mcc310-mnc800/config.xml
new file mode 100644
index 0000000..28cd695
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc800/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Configure mobile network MTU. Carrier specific value is set here.
+    -->
+    <integer name="config_mobile_mtu">1440</integer>
+
+    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_volte_vt_available">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 820cc2e..d0a57b3 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -38,10 +38,10 @@
         be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() -->
     <bool name="imsServiceAllowTurnOff">false</bool>
 
-    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+    <!-- Flag specifying whether VoLTE should be available for carrier: independent of
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
-    <bool name="config_carrier_volte_vt_available">true</bool>
+    <bool name="config_carrier_volte_available">true</bool>
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
     <!-- service number convert map in roaming network. -->
diff --git a/core/res/res/values-mcc530-mnc05/config.xml b/core/res/res/values-mcc530-mnc05/config.xml
new file mode 100644
index 0000000..893afe5
--- /dev/null
+++ b/core/res/res/values-mcc530-mnc05/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- If this value is true, The mms content-disposition field is supported correctly.
+         If false, Content-disposition fragments are ignored -->
+    <bool name="config_mms_content_disposition_support">false</bool>
+</resources>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 5773b94..46ec838 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -22,7 +22,7 @@
     <color name="background_floating_material_light">#ffeeeeee</color>
 
     <color name="primary_material_dark">#ff212121</color>
-    <color name="primary_material_light">#ffbdbdbd</color>
+    <color name="primary_material_light">#ffe0e0e0</color>
     <color name="primary_dark_material_dark">#ff000000</color>
     <color name="primary_dark_material_light">#ff757575</color>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 59b4e9c..e50eb0c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -453,6 +453,26 @@
     <!-- If this is true, key chords can be used to take a screenshot on the device. -->
     <bool name="config_enableScreenshotChord">true</bool>
 
+    <!-- If this is true, allow wake from theater mode when plugged in or unplugged. -->
+    <bool name="config_allowTheaterModeWakeFromUnplug">false</bool>
+    <!-- If this is true, allow wake from theater mode from gesture. -->
+    <bool name="config_allowTheaterModeWakeFromGesture">false</bool>
+    <!-- If this is true, allow wake from theater mode from camera lens cover is switched. -->
+    <bool name="config_allowTheaterModeWakeFromCameraLens">false</bool>
+    <!-- If this is true, allow wake from theater mode from power key press. -->
+    <bool name="config_allowTheaterModeWakeFromPowerKey">true</bool>
+    <!-- If this is true, allow wake from theater mode from regular key press. Setting this value to
+         true implies config_allowTheaterModeWakeFromPowerKey is also true-->
+    <bool name="config_allowTheaterModeWakeFromKey">false</bool>
+    <!-- If this is true, allow wake from theater mode from motion. -->
+    <bool name="config_allowTheaterModeWakeFromMotion">false</bool>
+    <!-- If this is true, allow wake from theater mode from lid switch. -->
+    <bool name="config_allowTheaterModeWakeFromLidSwitch">false</bool>
+    <!-- If this is true, allow wake from theater mode when docked. -->
+    <bool name="config_allowTheaterModeWakeFromDock">false</bool>
+    <!-- If this is true, allow wake from theater mode from window layout flag. -->
+    <bool name="config_allowTheaterModeWakeFromWindowLayout">false</bool>
+
     <!-- Auto-rotation behavior -->
 
     <!-- If true, enables auto-rotation features using the accelerometer.
@@ -1767,13 +1787,21 @@
         be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() -->
     <bool name="imsServiceAllowTurnOff">true</bool>
 
-    <!-- Flag specifying whether VoLTE & VT is availasble on device -->
-    <bool name="config_device_volte_vt_available">false</bool>
+    <!-- Flag specifying whether VoLTE is available on device -->
+    <bool name="config_device_volte_available">false</bool>
 
-    <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of
+    <!-- Flag specifying whether VoLTE should be available for carrier: independent of
          carrier provisioning. If false: hard disabled. If true: then depends on carrier
          provisioning, availability etc -->
-    <bool name="config_carrier_volte_vt_available">false</bool>
+    <bool name="config_carrier_volte_available">false</bool>
+
+    <!-- Flag specifying whether VT is available on device -->
+    <bool name="config_device_vt_available">false</bool>
+
+    <!-- Flag specifying whether VT should be available for carrier: independent of
+         carrier provisioning. If false: hard disabled. If true: then depends on carrier
+         provisioning, availability etc -->
+    <bool name="config_carrier_vt_available">false</bool>
 
     <bool name="config_networkSamplingWakesDevice">true</bool>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3d30792..56cf56d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1449,9 +1449,8 @@
     <string name="permlab_bodySensors">body sensors (like heart rate monitors)
     </string>
     <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_bodySensors" product="default">Allows the app to
-      access data from sensors you use to measure what’s happening inside your
-      body, such as heart rate.</string>
+    <string name="permdesc_bodySensors" product="default">Allows the app to access data from sensors
+    that monitor your physical condition, such as your heart rate.</string>
 
     <!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] -->
     <string name="permlab_readSocialStream" product="default">read your social stream</string>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index f9fca00..6e03b3d 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -320,49 +320,47 @@
         <item name="textColor">?attr/textColorPrimaryDisableOnly</item>
     </style>
 
-    <style name="TextAppearance.Material.Widget.ActionMode"/>
-    <style name="TextAppearance.Material.Widget.ActionMode.Title"
-           parent="TextAppearance.Material.Title">
-        <item name="textSize">@dimen/text_size_title_material_toolbar</item>
-    </style>
-    <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse"
-           parent="TextAppearance.Material.Title.Inverse">
-        <item name="textSize">@dimen/text_size_title_material_toolbar</item>
-    </style>
-    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle"
-           parent="TextAppearance.Material.Subhead">
-        <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
-    </style>
-    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"
-           parent="TextAppearance.Material.Subhead.Inverse">
-        <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
-    </style>
     <style name="TextAppearance.Material.Widget.ActionBar.Title"
            parent="TextAppearance.Material.Title">
         <item name="textSize">@dimen/text_size_title_material_toolbar</item>
+        <item name="textColor">?attr/textColorPrimary</item>
     </style>
     <style name="TextAppearance.Material.Widget.ActionBar.Title.Inverse"
            parent="TextAppearance.Material.Title.Inverse">
         <item name="textSize">@dimen/text_size_title_material_toolbar</item>
+        <item name="textColor">?attr/textColorPrimaryInverse</item>
     </style>
     <style name="TextAppearance.Material.Widget.ActionBar.Subtitle"
            parent="TextAppearance.Material.Subhead">
         <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
+        <item name="textColor">?attr/textColorSecondary</item>
     </style>
     <style name="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse"
            parent="TextAppearance.Material.Subhead.Inverse">
         <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item>
+        <item name="textColor">?attr/textColorSecondaryInverse</item>
     </style>
 
-    <style name="TextAppearance.Material.Widget.ActionBar.Menu" parent="TextAppearance.Material.Menu">
+    <style name="TextAppearance.Material.Widget.ActionBar.Menu"
+           parent="TextAppearance.Material.Menu">
+        <item name="textColor">?attr/actionMenuTextColor</item>
+        <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
+    </style>
+    <style name="TextAppearance.Material.Widget.ActionBar.Menu.Inverse"
+           parent="TextAppearance.Material.Menu.Inverse">
         <item name="textColor">?attr/actionMenuTextColor</item>
         <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
     </style>
 
-    <style name="TextAppearance.Material.Widget.ActionBar.Menu.Inverse" parent="TextAppearance.Material.Menu.Inverse">
-        <item name="textColor">?attr/actionMenuTextColor</item>
-        <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
-    </style>
+    <style name="TextAppearance.Material.Widget.ActionMode"/>
+    <style name="TextAppearance.Material.Widget.ActionMode.Title"
+           parent="TextAppearance.Material.Widget.ActionBar.Title" />
+    <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse"
+           parent="TextAppearance.Material.Widget.ActionBar.Title.Inverse" />
+    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle"
+           parent="TextAppearance.Material.Widget.ActionBar.Subtitle" />
+    <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"
+           parent="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse" />
 
     <style name="TextAppearance.Material.Widget.Toolbar.Title"
            parent="TextAppearance.Material.Widget.ActionBar.Title" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 71f0642..a11fdbc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1571,6 +1571,15 @@
   <java-symbol type="bool" name="config_enableNetworkLocationOverlay" />
   <java-symbol type="bool" name="config_sf_limitedAlpha" />
   <java-symbol type="bool" name="config_unplugTurnsOnScreen" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromUnplug" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromGesture" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromCameraLens" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromPowerKey" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromKey" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromMotion" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromLidSwitch" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" />
+  <java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" />
   <java-symbol type="bool" name="config_wifi_background_scan_support" />
   <java-symbol type="bool" name="config_wifi_dual_band_support" />
   <java-symbol type="bool" name="config_wimaxEnabled" />
@@ -2031,8 +2040,10 @@
   <java-symbol type="attr" name="preferenceFragmentStyle" />
   <java-symbol type="bool" name="skipHoldBeforeMerge" />
   <java-symbol type="bool" name="imsServiceAllowTurnOff" />
-  <java-symbol type="bool" name="config_device_volte_vt_available" />
-  <java-symbol type="bool" name="config_carrier_volte_vt_available" />
+  <java-symbol type="bool" name="config_device_volte_available" />
+  <java-symbol type="bool" name="config_carrier_volte_available" />
+  <java-symbol type="bool" name="config_device_vt_available" />
+  <java-symbol type="bool" name="config_carrier_vt_available" />
   <java-symbol type="bool" name="useImsAlwaysForEmergencyCall" />
   <java-symbol type="attr" name="touchscreenBlocksFocus" />
   <java-symbol type="layout" name="resolver_list_with_default" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 7e0467b..f1bc5da 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -24,6 +24,8 @@
         <item name="windowBackground">@color/black</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
+        <!-- We need the windows to be translucent for SwipeToDismiss layout
+             to work properly. -->
         <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
     </style>
@@ -38,6 +40,8 @@
         <item name="windowBackground">@color/white</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
+        <!-- We need the windows to be translucent for SwipeToDismiss layout
+             to work properly. -->
         <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
     </style>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index 80d5668..64fed7f 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -49,7 +49,8 @@
  */
 public class ConnectivityManagerTestBase extends InstrumentationTestCase {
 
-    private static final String PING_IP_ADDR = "8.8.8.8";
+    private static final String[] PING_HOST_LIST = {
+        "www.google.com", "www.yahoo.com", "www.bing.com", "www.facebook.com", "www.ask.com"};
 
     protected static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
     protected static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds
@@ -281,22 +282,14 @@
     }
 
     /**
-     * @param pingServerList a list of servers that can be used for ping test, can be null
      * @return true if the ping test is successful, false otherwise.
      */
-    protected boolean pingTest(String[] pingServerList) {
-        String[] hostList = {"www.google.com", "www.yahoo.com",
-                "www.bing.com", "www.facebook.com", "www.ask.com"};
-        if (pingServerList != null) {
-            hostList = pingServerList;
-        }
-
+    protected boolean pingTest() {
         long startTime = System.currentTimeMillis();
         while ((System.currentTimeMillis() - startTime) < PING_TIMER) {
             try {
                 // assume the chance that all servers are down is very small
-                for (int i = 0; i < hostList.length; i++ ) {
-                    String host = hostList[i];
+                for (String host : PING_HOST_LIST) {
                     logv("Start ping test, ping " + host);
                     Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
                     int status = p.waitFor();
@@ -312,6 +305,7 @@
             } catch (InterruptedException e) {
                 logv("Ping test Fail: InterruptedException");
             }
+            SystemClock.sleep(SHORT_TIMEOUT);
         }
         // ping test timeout
         return false;
@@ -458,14 +452,7 @@
     // use ping request against Google public DNS to verify connectivity
     protected boolean checkNetworkConnectivity() {
         assertTrue("no active network connection", waitForActiveNetworkConnection(LONG_TIMEOUT));
-        try {
-            Process proc = Runtime.getRuntime().exec(new String[]{
-                    "/system/bin/ping", "-W", "30", "-c", "1", PING_IP_ADDR});
-            return proc.waitFor() == 0;
-        } catch (InterruptedException | IOException e) {
-            Log.e(mLogTag, "Ping failed", e);
-        }
-        return false;
+        return pingTest();
     }
 
     @Override
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index d5051df..2d291ff 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -72,16 +72,6 @@
         super.tearDown();
     }
 
-    // help function to verify 3G connection
-    public void verifyCellularConnection() {
-        NetworkInfo extraNetInfo = mCm.getActiveNetworkInfo();
-        assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
-                extraNetInfo.getType());
-        assertTrue("not connected to cellular network", extraNetInfo.isConnected());
-    }
-
-
-
     // Test case 1: Test enabling Wifi without associating with any AP, no broadcast on network
     //              event should be expected.
     @LargeTest
@@ -336,4 +326,12 @@
         assertTrue("wifi state not disabled", waitForWifiState(
                 WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT));
     }
+
+    // help function to verify 3G connection
+    private void verifyCellularConnection() {
+        NetworkInfo extraNetInfo = mCm.getActiveNetworkInfo();
+        assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE,
+                extraNetInfo.getType());
+        assertTrue("not connected to cellular network", extraNetInfo.isConnected());
+    }
 }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index 41f01e6..de934b9 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -112,7 +112,7 @@
             } catch (Exception e) {
                 // ignore
             }
-            assertTrue("no uplink data connection after Wi-Fi tethering", pingTest(null));
+            assertTrue("no uplink data connection after Wi-Fi tethering", pingTest());
             // disable wifi hotspot
             assertTrue("failed to disable wifi hotspot",
                     mWifiManager.setWifiApEnabled(config, false));
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index fbd4669..f3d5c87 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -216,7 +216,7 @@
         assertTrue("wifi not connected", waitForNetworkState(ConnectivityManager.TYPE_WIFI,
                 State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
         // Run ping test to verify the data connection
-        assertTrue("Wi-Fi is connected, but no data connection.", pingTest(null));
+        assertTrue("Wi-Fi is connected, but no data connection.", pingTest());
 
         long i, sum = 0, avgReconnectTime = 0;
         for (i = 1; i <= mReconnectIterations; i++) {
@@ -264,7 +264,7 @@
             } else {
                 assertEquals("mobile not connected", State.CONNECTED,
                         mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
-                assertTrue("no connectivity over mobile", pingTest(null));
+                assertTrue("no connectivity over mobile", pingTest());
             }
 
             // Turn screen on again
@@ -281,7 +281,7 @@
             avgReconnectTime = sum / i;
             logv("average reconnection time is: " + avgReconnectTime);
 
-            assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null));
+            assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest());
         }
         Bundle result = new Bundle();
         result.putLong("actual-iterations", i - 1);
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index b524177..226717e 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1252,6 +1252,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.content.res.ResourceCacheActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/core/tests/coretests/res/anim/reset_state_anim.xml b/core/tests/coretests/res/anim/reset_state_anim.xml
index 918d0a3..4bbbe62 100644
--- a/core/tests/coretests/res/anim/reset_state_anim.xml
+++ b/core/tests/coretests/res/anim/reset_state_anim.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+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.
+-->
 <set xmlns:android="http://schemas.android.com/apk/res/android">
     <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
     <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
diff --git a/core/tests/coretests/res/anim/test_animator.xml b/core/tests/coretests/res/anim/test_animator.xml
new file mode 100644
index 0000000..49afc3f
--- /dev/null
+++ b/core/tests/coretests/res/anim/test_animator.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- if you change this, you should also change AnimatorInflaterTest#testLoadAnimator-->
+    <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="1" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="left" android:duration="100" android:valueTo="2" android:valueType="intType"/>
+</set>
\ No newline at end of file
diff --git a/core/tests/coretests/res/anim/test_state_anim.xml b/core/tests/coretests/res/anim/test_state_anim.xml
index 9e08f68..b6a4822 100644
--- a/core/tests/coretests/res/anim/test_state_anim.xml
+++ b/core/tests/coretests/res/anim/test_state_anim.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+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.
+-->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true">
         <set>
diff --git a/core/tests/coretests/res/values-land/dimens.xml b/core/tests/coretests/res/values-land/dimens.xml
new file mode 100644
index 0000000..1ee9f1d
--- /dev/null
+++ b/core/tests/coretests/res/values-land/dimens.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+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.
+-->
+<resources>
+    <dimen name="resource_cache_test_orientation_dependent">3dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/tests/coretests/res/values/dimens.xml b/core/tests/coretests/res/values/dimens.xml
new file mode 100644
index 0000000..00fc414
--- /dev/null
+++ b/core/tests/coretests/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+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.
+-->
+<resources>
+    <dimen name="resource_cache_test_generic">10dp</dimen>
+    <dimen name="resource_cache_test_orientation_dependent">20dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
new file mode 100644
index 0000000..3c81853
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* 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.
+*/
+package android.animation;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.android.frameworks.coretests.R;
+
+public class AnimatorInflaterTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity>  {
+    Set<Integer> identityHashes = new HashSet<Integer>();
+
+    public AnimatorInflaterTest() {
+        super(BasicAnimatorActivity.class);
+    }
+
+    private void assertUnique(Object object) {
+        assertUnique(object, "");
+    }
+
+    private void assertUnique(Object object, String msg) {
+        final int code = System.identityHashCode(object);
+        assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code));
+
+    }
+
+    public void testLoadStateListAnimator() {
+        StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(getActivity(),
+                R.anim.test_state_anim);
+        sla1.setTarget(getActivity().mAnimatingButton);
+        StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(getActivity(),
+                R.anim.test_state_anim);
+        assertNull(sla2.getTarget());
+        for (StateListAnimator sla : new StateListAnimator[]{sla1, sla2}) {
+            assertUnique(sla);
+            assertEquals(3, sla.getTuples().size());
+            for (StateListAnimator.Tuple tuple : sla.getTuples()) {
+                assertUnique(tuple);
+                assertUnique(tuple.getAnimator());
+            }
+        }
+    }
+
+}
diff --git a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
index 93808d9..6bcf8fc 100644
--- a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
+++ b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
@@ -19,11 +19,14 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.Button;
 
 public class BasicAnimatorActivity extends Activity {
+    public Button mAnimatingButton;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.animator_basic);
+        mAnimatingButton = (Button) findViewById(R.id.animatingButton);
     }
 }
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
new file mode 100644
index 0000000..e9fd5fb
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package android.content.res;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.TypedValue;
+
+import com.android.frameworks.coretests.R;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class ConfigurationBoundResourceCacheTest
+        extends ActivityInstrumentationTestCase2<ResourceCacheActivity> {
+
+    ConfigurationBoundResourceCache<Float> mCache;
+
+    Method mCalcConfigChanges;
+
+    public ConfigurationBoundResourceCacheTest() {
+        super(ResourceCacheActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mCache = new ConfigurationBoundResourceCache<Float>(getActivity().getResources());
+    }
+
+    public void testGetEmpty() {
+        assertNull(mCache.get(-1, null));
+    }
+
+    public void testSetGet() {
+        mCache.put(1, null, new DummyFloatConstantState(5f));
+        assertEquals(5f, mCache.get(1, null));
+        assertNotSame(5f, mCache.get(1, null));
+        assertEquals(null, mCache.get(1, getActivity().getTheme()));
+    }
+
+    public void testSetGetThemed() {
+        mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f));
+        assertEquals(null, mCache.get(1, null));
+        assertEquals(5f, mCache.get(1, getActivity().getTheme()));
+        assertNotSame(5f, mCache.get(1, getActivity().getTheme()));
+    }
+
+    public void testMultiThreadPutGet() {
+        mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f));
+        mCache.put(1, null, new DummyFloatConstantState(10f));
+        assertEquals(10f, mCache.get(1, null));
+        assertNotSame(10f, mCache.get(1, null));
+        assertEquals(5f, mCache.get(1, getActivity().getTheme()));
+        assertNotSame(5f, mCache.get(1, getActivity().getTheme()));
+    }
+
+    public void testVoidConfigChange()
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        TypedValue staticValue = new TypedValue();
+        long key = 3L;
+        final Resources res = getActivity().getResources();
+        res.getValue(R.dimen.resource_cache_test_generic, staticValue, true);
+        float staticDim = TypedValue.complexToDimension(staticValue.data, res.getDisplayMetrics());
+        mCache.put(key, getActivity().getTheme(),
+                new DummyFloatConstantState(staticDim, staticValue.changingConfigurations));
+        final Configuration cfg = res.getConfiguration();
+        Configuration newCnf = new Configuration(cfg);
+        newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        int changes = calcConfigChanges(res, newCnf);
+        assertEquals(staticDim, mCache.get(key, getActivity().getTheme()));
+        mCache.onConfigurationChange(changes);
+        assertEquals(staticDim, mCache.get(key, getActivity().getTheme()));
+    }
+
+    public void testEffectiveConfigChange()
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        TypedValue changingValue = new TypedValue();
+        long key = 4L;
+        final Resources res = getActivity().getResources();
+        res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValue, true);
+        float changingDim = TypedValue.complexToDimension(changingValue.data,
+                res.getDisplayMetrics());
+        mCache.put(key, getActivity().getTheme(),
+                new DummyFloatConstantState(changingDim, changingValue.changingConfigurations));
+
+        final Configuration cfg = res.getConfiguration();
+        Configuration newCnf = new Configuration(cfg);
+        newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        int changes = calcConfigChanges(res, newCnf);
+        assertEquals(changingDim, mCache.get(key, getActivity().getTheme()));
+        mCache.onConfigurationChange(changes);
+        assertNull(mCache.get(key, getActivity().getTheme()));
+    }
+
+    public void testConfigChangeMultipleResources()
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        TypedValue staticValue = new TypedValue();
+        TypedValue changingValue = new TypedValue();
+        final Resources res = getActivity().getResources();
+        res.getValue(R.dimen.resource_cache_test_generic, staticValue, true);
+        res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValue, true);
+        float staticDim = TypedValue.complexToDimension(staticValue.data, res.getDisplayMetrics());
+        float changingDim = TypedValue.complexToDimension(changingValue.data,
+                res.getDisplayMetrics());
+        mCache.put(R.dimen.resource_cache_test_generic, getActivity().getTheme(),
+                new DummyFloatConstantState(staticDim, staticValue.changingConfigurations));
+        mCache.put(R.dimen.resource_cache_test_orientation_dependent, getActivity().getTheme(),
+                new DummyFloatConstantState(changingDim, changingValue.changingConfigurations));
+        final Configuration cfg = res.getConfiguration();
+        Configuration newCnf = new Configuration(cfg);
+        newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        int changes = calcConfigChanges(res, newCnf);
+        assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic,
+                getActivity().getTheme()));
+        assertEquals(changingDim, mCache.get(R.dimen.resource_cache_test_orientation_dependent,
+                getActivity().getTheme()));
+        mCache.onConfigurationChange(changes);
+        assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic,
+                getActivity().getTheme()));
+        assertNull(mCache.get(R.dimen.resource_cache_test_orientation_dependent,
+                getActivity().getTheme()));
+    }
+
+    public void testConfigChangeMultipleThemes()
+            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+        TypedValue[] staticValues = new TypedValue[]{new TypedValue(), new TypedValue()};
+        TypedValue[] changingValues = new TypedValue[]{new TypedValue(), new TypedValue()};
+        float staticDim = 0;
+        float changingDim = 0;
+        final Resources res = getActivity().getResources();
+        for (int i = 0; i < 2; i++) {
+            res.getValue(R.dimen.resource_cache_test_generic, staticValues[i], true);
+            staticDim = TypedValue
+                    .complexToDimension(staticValues[i].data, res.getDisplayMetrics());
+
+            res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValues[i],
+                    true);
+            changingDim = TypedValue.complexToDimension(changingValues[i].data,
+                    res.getDisplayMetrics());
+            final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
+            mCache.put(R.dimen.resource_cache_test_generic, theme,
+                    new DummyFloatConstantState(staticDim, staticValues[i].changingConfigurations));
+            mCache.put(R.dimen.resource_cache_test_orientation_dependent, theme,
+                    new DummyFloatConstantState(changingDim,
+                            changingValues[i].changingConfigurations));
+        }
+        final Configuration cfg = res.getConfiguration();
+        Configuration newCnf = new Configuration(cfg);
+        newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        int changes = calcConfigChanges(res, newCnf);
+        for (int i = 0; i < 2; i++) {
+            final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
+            assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, theme));
+            assertEquals(changingDim,
+                    mCache.get(R.dimen.resource_cache_test_orientation_dependent, theme));
+        }
+        mCache.onConfigurationChange(changes);
+        for (int i = 0; i < 2; i++) {
+            final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null;
+            assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, theme));
+            assertNull(mCache.get(R.dimen.resource_cache_test_orientation_dependent, theme));
+        }
+    }
+
+    private int calcConfigChanges(Resources resources, Configuration configuration)
+            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+        if (mCalcConfigChanges == null) {
+            mCalcConfigChanges = Resources.class.getDeclaredMethod("calcConfigChanges",
+                    Configuration.class);
+            mCalcConfigChanges.setAccessible(true);
+        }
+        return (Integer) mCalcConfigChanges.invoke(resources, configuration);
+
+    }
+
+    static class DummyFloatConstantState extends
+            ConstantState<Float> {
+
+        final Float mObj;
+
+        int mChangingConf = 0;
+
+        DummyFloatConstantState(Float obj) {
+            mObj = obj;
+        }
+
+        DummyFloatConstantState(Float obj, int changingConf) {
+            mObj = obj;
+            mChangingConf = changingConf;
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConf;
+        }
+
+        @Override
+        public Float newInstance() {
+            return new Float(mObj);
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java b/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java
new file mode 100644
index 0000000..f37e549
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java
@@ -0,0 +1,37 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* 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.
+*/
+
+package android.content.res;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+
+import java.lang.ref.WeakReference;
+
+public class ResourceCacheActivity extends Activity {
+    static WeakReference<ResourceCacheActivity> lastCreatedInstance;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        lastCreatedInstance = new WeakReference<ResourceCacheActivity>(this);
+    }
+
+    public static ResourceCacheActivity getLastCreatedInstance() {
+        return lastCreatedInstance == null ? null : lastCreatedInstance.get();
+    }
+}
diff --git a/docs/html/about/versions/android-5.0.jd b/docs/html/about/versions/android-5.0.jd
index f8d8ab6..a438420 100644
--- a/docs/html/about/versions/android-5.0.jd
+++ b/docs/html/about/versions/android-5.0.jd
@@ -23,6 +23,7 @@
 <li><a href="#BehaviorGetRecentTasks">If your app uses getRecentTasks()...</a></li>
 <li><a href="#64BitSupport">If you are using the Android Native Development Kit (NDK)...</a></li>
 <li><a href="#BindService">If your app binds to a Service...</a></li>
+<li><a href="#BehaviorWebView">If your app uses a WebView...</a></li>
     </ol>
   </li>
   <li><a href="#UI">User Interface</a>
@@ -234,8 +235,8 @@
 vibration.</p>
 
 <p>Setting the device to
-{@link android.media.AudioManager#RINGER_MODE_SILENT RINGER_MODE_SILENT} now
-causes the device to enter the new priority mode. The device leaves priority
+{@link android.media.AudioManager#RINGER_MODE_SILENT RINGER_MODE_SILENT} causes
+the device to enter the new priority mode. The device leaves priority
 mode if you set it to
 {@link android.media.AudioManager#RINGER_MODE_NORMAL RINGER_MODE_NORMAL} or
 {@link android.media.AudioManager#RINGER_MODE_NORMAL RINGER_MODE_VIBRATE}.</p>
@@ -366,6 +367,31 @@
 To ensure your app is secure, use an explicit intent when starting or binding
 your {@link android.app.Service}, and do not declare intent filters for the service.</p>
 
+<h3 id="BehaviorWebView">If your app uses WebView...</h3>
+
+<p>Android 5.0 changes the default behavior for your app.</p>
+<ul>
+<li><strong>If your app targets API level 21 or higher:</strong>
+  <ul>
+    <li>The system
+  blocks <a href="https://developer.mozilla.org/en-US/docs/Security/MixedContent"
+  class="external-link">mixed content</a> and third party cookies by default. To allow mixed
+  content and third party cookies, use the
+  {@link android.webkit.WebSettings#setMixedContentMode(int) setMixedContentMode()}
+and {@link android.webkit.CookieManager#setAcceptThirdPartyCookies(android.webkit.WebView, boolean) setAcceptThirdPartyCookies()}
+methods respectively.</li>
+    <li>The system now intelligently chooses portions of the HTML
+      document to draw. This new default behavior helps to reduce memory
+      footprint and increase performance. If you want to
+      render the whole document at once, disable this optimization by calling
+      {@link android.webkit.WebView#enableSlowWholeDocumentDraw()}.</li>
+  </ul>
+</li>
+<li><strong>If your app targets API levels lower than 21:</strong> The system
+  allows mixed content and third party cookies, and always renders the whole
+  document at once.</li>
+</ul>
+
 <h2 id="UI">User Interface</h2>
 
 <h3 id="MaterialDesign">Material design support</h3>
@@ -470,7 +496,7 @@
 method.</p>
 
 <p>For an example of how to use the new APIs, see the {@code MediaProjectionDemo}
-class in the {@code ApiDemos} sample project.</p>
+class in the sample project.</p>
 
 <h2 id="Notifications">Notifications</h2>
 
diff --git a/docs/html/about/versions/lollipop.jd b/docs/html/about/versions/lollipop.jd
index 085dc24..3ee0a86 100644
--- a/docs/html/about/versions/lollipop.jd
+++ b/docs/html/about/versions/lollipop.jd
@@ -206,15 +206,16 @@
 <p>Android 5.0 also adds support for <strong>multimedia tunneling</strong> to provide the best experience for ultra-high definition (4K) content and the ability to play compressed audio and video data together. </p>
 
 
-<!--
+
 <div class="figure" style="width:320px; margin:1em 0 0 20px;padding-left:2em;">
 <img style="float:right; margin:0 1em 1em 2em"
     src="{@docRoot}images/android-5.0/managed_apps_launcher@2x.png"
     srcset="{@docRoot}images/android-5.0/managed_apps_launcher@2x.png 2x"
     alt="" width="300" />
-<p class="img-caption">Android Work users have a unified view of their personal and work apps, which are badged for easy identification.</p>
+<p class="img-caption">Users have a unified view of their personal and work apps, which are
+badged for easy identification.</p>
 </div>
--->
+
 
 <h2 id="Work">Android in the workplace</h2>
 
diff --git a/docs/html/distribute/essentials/essentials_toc.cs b/docs/html/distribute/essentials/essentials_toc.cs
index 4e53468..a1c9575 100644
--- a/docs/html/distribute/essentials/essentials_toc.cs
+++ b/docs/html/distribute/essentials/essentials_toc.cs
@@ -17,6 +17,12 @@
     </div>
   </li>
   <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/wear.html">
+            <span class="en">Wear App Quality</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
     <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/optimizing-your-app.html">
           <span class="en">Optimize Your App</span>
         </a>
diff --git a/docs/html/distribute/essentials/quality/tv.jd b/docs/html/distribute/essentials/quality/tv.jd
index 8e17157..b13307e 100644
--- a/docs/html/distribute/essentials/quality/tv.jd
+++ b/docs/html/distribute/essentials/quality/tv.jd
@@ -234,7 +234,7 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      App does not depend on a remote controller having a menu button to access user interface
+      App does not depend on a remote controller having a Menu button to access user interface
       controls.
       (<a href="{@docRoot}training/tv/start/navigation.html#d-pad-navigation">Learn how</a>)
     </p>
@@ -291,8 +291,8 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      App manifest sets an intent type of {@code ACTION_MAIN} with category
-      {@code CATEGORY_LEANBACK_LAUNCHER}.
+      App manifest sets an intent type of {@link android.content.Intent#ACTION_MAIN} with category
+      {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER}.
       (<a href="{@docRoot}training/tv/start/start.html#tv-activity">Learn how</a>)
     </p>
   </td>
@@ -321,8 +321,9 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      If the app requires a game controller, the app manifest sets the {@code uses-feature} setting
-      {@code android.hardware.gamepad} to {@code required="true"}.
+      If the app uses a game controller as it's primary input method, it declares the appropriate
+      requirement with the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"
+      >{@code &lt;uses-feature>}</a> manifest tag.
       (<a href="{@docRoot}training/tv/games/index.html#gamepad">Learn how</a>)
     </p>
   </td>
@@ -334,9 +335,9 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      If the app provides user instructions for use of game controllers, the instructions
-      do not include a controller with any branding.
-      (<a href="{@docRoot}training/tv/games/index.html#generic-controllers">Learn how</a>)
+      If the app provides visual instructions for using game controllers, the instructions should
+      be free of branding and show a compatible button layout.
+      (<a href="{@docRoot}training/tv/games/index.html#ControllerHelp">Learn how</a>)
     </p>
   </td>
 </tr>
@@ -351,7 +352,7 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      App enables interaction with any advertising using D-pad controls.
+      App allows interaction with advertising using D-pad controls.
       (<a href="{@docRoot}training/tv/start/navigation.html#d-pad-navigation">Learn how</a>)
     </p>
   </td>
@@ -363,7 +364,7 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      For advertising that uses full-screen, non-video ads, the app allows the user to
+      For advertising that uses fullscreen, non-video ads, the app allows the user to
       immediately dismiss the ad with D-pad controls.
     </p>
   </td>
@@ -375,7 +376,7 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      For advertising that uses clickable, non-full screen, non-video ads, the app does not allow
+      For advertising that uses clickable, non-fullscreen, non-video ads, the app does not allow
       ads to link to a web URL.
     </p>
   </td>
@@ -387,7 +388,7 @@
   </td>
   <td>
     <p style="margin-bottom:.5em;">
-      For advertising that uses clickable, non-full screen, non-video ads, the app does not allow
+      For advertising that uses clickable, non-fullscreen, non-video ads, the app does not allow
       ads to link to another app that is not available on TV devices.
     </p>
   </td>
diff --git a/docs/html/distribute/essentials/quality/wear.jd b/docs/html/distribute/essentials/quality/wear.jd
new file mode 100644
index 0000000..aa3e126
--- /dev/null
+++ b/docs/html/distribute/essentials/quality/wear.jd
@@ -0,0 +1,389 @@
+page.title=Wear App Quality
+page.tags="wear","wearables","quality","guidelines"
+page.metaDescription=Wearables are small factor devices that are built for glanceability and require unique design and functionality.
+page.image=/distribute/images/gp-wear-quality.png
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Quality Criteria</h2>
+  <ol>
+    <li><a href="#ux">Design and Interaction</a></li>
+    <li><a href="#fn">Functionality</a></li>
+    <li><a href="#faq">Frequently Asked Questions</a></li>
+  </ol>
+
+  <h2>You Should Also Read</h2>
+  <ol>
+    <li><a href="{@docRoot}distribute/essentials/quality/core.html">
+      Core App Quality</a></li>
+    <li><a href="{@docRoot}distribute/essentials/optimizing-your-app.html">
+      Optimize Your App</a></li>
+    <li><a href="{@docRoot}design/patterns/notifications.html">
+      Notifications</a></li>
+  </ol>
+</div>
+</div>
+
+<div class="top-right-float" style="padding-right:0;margin-bottom:1em;">
+  <img src="{@docRoot}distribute/images/gp-wear-quality.png" style="width:460px;">
+</div>
+
+<p>
+  Android Wear aims to provide users with just the right information at just the right time. Great
+  Android Wear experiences are launched automatically, glanceable, and require zero or low user
+  interaction. Designing apps for wearables is substantially different than designing for phones or
+  tablets. There are different strengths and weaknesses, different use cases, and different
+  ergonomics to take into consideration.
+</p>
+
+<p>
+  The first step toward creating a great experience for users on Wear is to read the
+  <a href="{@docRoot}design/wear/index.html">Android Wear design guidelines</a>, which provides
+  instructions on how to build the best user experience for Wear apps. You should also review the
+  <a href="{@docRoot}training/building-wearables.html">Building Apps for Wearables</a> training, to
+  understand the basic implementation requirements for a Wear app.
+</p>
+
+<p class="caution">
+  <strong>Important:</strong> To ensure a great user experience, apps for wearables must meet
+  specific requirements for usability. Only apps that meet the following quality criteria will
+  qualify as an Android Wear app on Google Play. Qualifying as a Wear app will make it easier for
+  Android Wear users to discover your app on Google Play.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> You will be able to submit your apps for Android Wear review when the
+ public release of Android 5.0 launches on November 3. Stay tuned for more information about how to
+ submit your apps for Android Wear review through the <a href="https://play.google.com/apps/publish/signup/">Google Play Developer Console</a>.
+</p>
+
+<div class="headerLine">
+  <h2 id="fn">
+  Functionality
+  </h2>
+
+
+</div>
+
+<p>
+  These criteria ensure that your app is configured correctly and provides the expected
+  functional behavior.
+</p>
+
+
+<table>
+<tr>
+  <th style="width:2px;">
+    Type
+  </th>
+  <th style="width:54px;">
+    ID
+  </th>
+  <th>
+    Description
+  </th>
+</tr>
+
+<tr>
+  <td rowspan="1" id="general">
+   General
+  </td>
+
+  <td id="WR-GL">
+    WR-GL
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Handheld app includes either notifications with wearable-specific functionality or a wearable
+      app that runs directly on the Wear device.
+      (<a href="{@docRoot}training/building-wearables.html">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td rowspan="1" id="packaging">
+   Packaging
+  </td>
+
+  <td id="WR-PK">
+    WR-PK
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Wearable apps that run directly on the device are packaged inside the primary handheld app.
+      (<a href="{@docRoot}training/wearables/apps/packaging.html">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+
+<tr>
+  <td rowspan="3" id="functional-notifications">
+    Notifications
+  </td>
+
+  <td id="WR-FW">
+    WR-FW
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Notifications with wearable-specific functionality use a {@code RemoteInput} or
+      {@code WearableExtender}.
+      (<a href="{@docRoot}training/wearables/notifications/index.html">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td id="WR-FR">
+    WR-FR
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Notifications for messaging apps allow users to reply via voice input or quick responses.
+      (<a href="{@docRoot}training/wearables/notifications/voice-input.html">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td id="WR-FG">
+    WR-FG
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Similar notifications are grouped together in a stack.
+      (<a href="{@docRoot}training/wearables/notifications/stacks.html">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td rowspan="1" id="gestures">
+    Gestures
+  </td>
+
+  <td id="WR-GP">
+    WR-GP
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Full-screen activities use long press for the sole purpose of prompting to quit.
+      <br/>
+      (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+</table>
+
+
+<h3 class="rel-resources clearfloat">Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/wearqualityguidelines/functionality"
+data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
+</div>
+
+<div class="headerLine">
+  <h2 id="ux">
+  Visual Design and User Interaction
+  </h2>
+
+
+</div>
+
+<p>
+  These criteria ensure that your app follows critical design and interaction patterns to provide a
+  consistent, intuitive, and enjoyable user experience on wearables.
+</p>
+
+<table>
+
+<tr>
+  <th style="width:2px;">
+    Type
+  </th>
+  <th style="width:54px;">
+    ID
+  </th>
+  <th>
+    Description
+  </th>
+</tr>
+
+<tr>
+  <td rowspan="2" id="layout">
+    Layout
+  </td>
+
+  <td id="WR-LL">
+    WR-LL
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      App user interface is formatted appropriately for both square and round displays.
+      (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td id="WR-TC">
+    WR-TC
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      App text is large and glanceable with a suggested minimum size of 16sp.
+      (<a href="{@docRoot}design/wear/style.html#Typography">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td rowspan="1" id="launcher">
+    Launcher
+  </td>
+
+  <td id="WR-LN">
+    WR-LN
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      App launcher string is the app name, not a command phrase.
+      (<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td rowspan="5" id="notifications">
+    Notifications
+  </td>
+
+  <td id="WR-NC">
+    WR-NC
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      App displays confirmation animations when appropriate.
+      (<a href="{@docRoot}design/wear/patterns.html#Countdown">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td id="WR-NR">
+    WR-NR
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Notification cards have the app icon visible at the top right edge. The one exception is if the
+      notification card has single-action controls, for example a media playback card.
+      <br/>
+      (<a href="{@docRoot}design/wear/style.html#Assets">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td id="WR-WI">
+    WR-WI
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Notification actions have a white icon, action title, and transparent background.
+      <br/>
+      (<a href="{@docRoot}training/wearables/notifications/creating.html#ActionButtons">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td id="WR-PB">
+    WR-PB
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Notification photo backgrounds are used only to convey information, not to brand a card.
+      (<a href="{@docRoot}design/wear/style.html#Branding">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td id="WR-PR">
+    WR-PR
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      Notification photo backgrounds have a resolution of at least 400x400.
+      (<a href="{@docRoot}training/wearables/notifications/creating.html#AddWearableFeatures">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+<tr>
+  <td rowspan="1" id="googleplay">
+    Google Play
+  </td>
+
+  <td id="WR-GS">
+    WR-GS
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+      App includes at least one Wear screenshot in Play details page.
+      (<a href="https://support.google.com/googleplay/android-developer/answer/1078870?hl=en">Learn how</a>)
+    </p>
+  </td>
+</tr>
+
+</table>
+
+
+<h3 class="rel-resources clearfloat">Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/wearqualityguidelines/visualdesign"
+data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6">
+</div>
+
+<div class="headerLine">
+  <h2 id="faq">
+  Frequently Asked Questions
+  </h2>
+</div>
+
+<p style="margin-top:30px;">
+  <strong>After I submit my app for Android Wear review, how will I find out if my app does not meet
+  all the requirements for Wear?</strong>
+</p>
+<p>
+  If your app does not meet the usability requirements described on this page, the Play Store team
+  will contact you through the email address specified in the <a href=
+  "https://play.google.com/apps/publish/">Google Play Developer Console</a> account associated with
+  the app.
+</p>
+<p class="caution">
+  <strong>Caution:</strong> Make sure your app meets the <a href="#fn">functionality
+  requirements</a>, otherwise your app will not be considered a Wear app and will not be reviewed
+  for Wear <a href="#ux">design and interaction</a>.
+</p>
+<p class="note">
+ <strong>Note:</strong> You will be able to submit your apps for additional Android Wear review when
+ the public release of Android 5.0 launches on November 3.
+</p>
+
+
+<p style="margin-top:30px;">
+  <strong>If my app does not meet the Wear requirements, will my new or updated app still appear on
+  Google Play for phones and tablets and still be installable on wearables?</strong>
+</p>
+<p>
+  Yes. The requirements described above only determine whether your app will be identified as an
+  Android Wear app on Google Play and easier for Android Wear users to discover. If your app is not
+  accepted as a Wear app, it will still be available to other device types, such as phones and
+  tablets, and it will still be installable on wearables.
+</p>
diff --git a/docs/html/distribute/images/gp-wear-quality.png b/docs/html/distribute/images/gp-wear-quality.png
new file mode 100644
index 0000000..41ae2bc
--- /dev/null
+++ b/docs/html/distribute/images/gp-wear-quality.png
Binary files differ
diff --git a/docs/html/images/android-5.0/managed_apps_launcher.png b/docs/html/images/android-5.0/managed_apps_launcher.png
index 8184556..46e4c74 100644
--- a/docs/html/images/android-5.0/managed_apps_launcher.png
+++ b/docs/html/images/android-5.0/managed_apps_launcher.png
Binary files differ
diff --git a/docs/html/images/android-5.0/managed_apps_launcher@2x.png b/docs/html/images/android-5.0/managed_apps_launcher@2x.png
index 66b7be9..d7fdbce 100644
--- a/docs/html/images/android-5.0/managed_apps_launcher@2x.png
+++ b/docs/html/images/android-5.0/managed_apps_launcher@2x.png
Binary files differ
diff --git a/docs/html/images/games/game-controller-buttons.png b/docs/html/images/games/game-controller-buttons.png
new file mode 100644
index 0000000..b3e458a
--- /dev/null
+++ b/docs/html/images/games/game-controller-buttons.png
Binary files differ
diff --git a/docs/html/images/games/game-controller-buttons_2x.png b/docs/html/images/games/game-controller-buttons_2x.png
new file mode 100644
index 0000000..7a0ad0b
--- /dev/null
+++ b/docs/html/images/games/game-controller-buttons_2x.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index c49f8cc..08c0090 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -67,9 +67,9 @@
       "distribute/essentials/quality/core.html",
       "distribute/essentials/quality/tablets.html",
       "distribute/essentials/quality/tv.html",
+      "distribute/essentials/quality/wear.html",
       "https://developers.google.com/edu/guidelines",
-      "distribute/essentials/optimizing-your-app.html",
-      "distribute/essentials/best-practices/games.html"
+      "distribute/essentials/optimizing-your-app.html"
     ]
   },
   "distribute/users": {
@@ -332,6 +332,22 @@
       "training/tv/games/index.html"
     ]
   },
+  "distribute/essentials/wearqualityguidelines/visualdesign": {
+    "title": "",
+    "resources": [
+      "design/wear/index.html",
+      "training/building-wearables.html",
+      "training/wearables/ui/index.html"
+    ]
+  },
+  "distribute/essentials/wearqualityguidelines/functionality": {
+    "title": "",
+    "resources": [
+      "training/wearables/notifications/index.html",
+      "training/wearables/apps/index.html",
+      "training/wearables/notifications/voice-input.html"
+    ]
+  },
   "distribute/essentials/core/performance": {
     "title": "",
     "resources": [
diff --git a/docs/html/samples/new/index.jd b/docs/html/samples/new/index.jd
index 523b922..330caa3 100644
--- a/docs/html/samples/new/index.jd
+++ b/docs/html/samples/new/index.jd
@@ -348,3 +348,18 @@
 </p>
 
 <p><a href="http://github.com/googlesamples/android-AppRestrictionSchema">Get it on GitHub</a></p>
+
+<h3 id="SpeedTracker">Speed Tracker (Wear)</h3>
+
+<p>
+This sample uses the FusedLocation APIs of Google Play Services on Android Wear 
+devices that have a hardware GPS built in. In those cases, this sample provides
+a simple screen that shows the current speed of the wearable device. User can
+set a speed limit and if the speed approaches that limit, it changes the color
+to yellow and if it exceeds the limit, it turns red. User can also enable
+recording of coordinates and when it pairs back with the phone, this data
+is synced with the phone component of the app and user can see a track
+made of those coordinates on a map on the phone.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-SpeedTracker">Get it on GitHub</a></p>
diff --git a/docs/html/sdk/installing/adding-packages.jd b/docs/html/sdk/installing/adding-packages.jd
index e6c0118..22d055c 100644
--- a/docs/html/sdk/installing/adding-packages.jd
+++ b/docs/html/sdk/installing/adding-packages.jd
@@ -1,5 +1,8 @@
 page.title=Adding SDK Packages
 
+page.tags=studio, sdk tools, eclipse adt, sdk manager, google play services, support library
+helpoutsWidget=true
+
 @jd:body
 
 <style>
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index ec0e2f8..6a99952 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -1,5 +1,8 @@
 page.title=Installing the Android SDK
 
+page.tags=studio, sdk tools, eclipse adt
+helpoutsWidget=true
+
 @jd:body
 
 <style>
diff --git a/docs/html/support.jd b/docs/html/support.jd
index 4271eee..bbed7df 100644
--- a/docs/html/support.jd
+++ b/docs/html/support.jd
@@ -3,6 +3,7 @@
 fullpage=1
 page.metaDescription=Resources available to help you report and resolve issues while you are developing apps for Android.
 page.image=/images/android-support-card.png
+
 @jd:body
 
 <div class="wrap" style="width:940px;">
@@ -28,13 +29,20 @@
   <a href="http://webchat.freenode.net/?channels=android">#android</a>, <a href="http://webchat.freenode.net/?channels=android-dev">#android-dev</a> <span style="color:#888">(IRC via irc.freenode.net)</span><br />
 </p>
 
+<p><b>
+<a target="_blank"
+href="https://helpouts.google.com/partner/ask?vertical=programming&tags=android&origin=http:%2F%2Fdeveloper.android.com%2Fsupport.html">Ask a question in Google Helpouts</a>
+</b></p>
+
 
 <h5>Send Feedback</h5>
 <p>
   <a href="http://code.google.com/p/android/issues/entry?template=Developer%20Documentation">Report documentation bug</a><br />
   <a href="https://code.google.com/p/android/issues/entry?template=User%20bug%20report">Report device bug</a><br />
   <a href="https://code.google.com/p/android/issues/entry?template=Developer%20bug%20report">Report platform bug</a><br />
-  
+</p>
+
+
   </div>
 
   
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index fe78ce9..6f07755 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -77,6 +77,28 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 21.0.2</a> <em>(October 2014)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Complete updates for Eclipse ADT to solve instability issues on Windows platforms.</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 21.0.1</a> <em>(October 2014)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Initial updates for Eclipse ADT on Windows. Please use Revision 21.0.2.</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Build Tools, Revision 21.0.0</a> <em>(October 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
@@ -96,6 +118,7 @@
   </div>
 </div>
 
+
 <div class="toggle-content closed">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index 3fa1b9b..85b9c5e 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -80,6 +80,23 @@
 
 <h2 id="4.4">Android 4.4W</h2>
 
+<div class="toggle-content open">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-open.png"
+class="toggle-content-img" alt="" />Revision 2</a> <em>(October 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <p>Added location APIs support for Wear.</p>
+
+    <p>Dependencies:</p>
+    <ul>
+      <li>Android SDK Platform-tools r20 or higher is required.</li>
+      <li>Android SDK Tools 23.0 or higher is required.</li>
+    </ul>
+  </div>
+
 <div class="toggle-content closed">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-closed.png"
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 8311097..44c5045 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -139,10 +139,10 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:support-v4:18.0.+
+com.android.support:support-v4:21.0.+
 </pre>
 
-<p>This dependency notation specifies the release version 18.0.0 or higher.</p>
+<p>This dependency notation specifies the release version 21.0.0 or higher.</p>
 
 
 <h2 id="v7">v7 Support Libraries</h2>
@@ -237,10 +237,10 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:gridlayout-v7:18.0.+
+com.android.support:gridlayout-v7:21.0.+
 </pre>
 
-<p>This dependency notation specifies the release version 18.0.0 or higher.</p>
+<p>This dependency notation specifies the release version 21.0.0 or higher.</p>
 
 
 <h3 id="v7-mediarouter">v7 mediarouter library</h3>
@@ -271,10 +271,10 @@
 
 <p>If you are using Android Studio, all you need to do is specify the Gradle build
 script dependency identifier <code>com.android.support:support-v7-mediarouter:&lt;revision&gt;</code>,
-where "18.0.0" is the minimum revision at which the library is available. For example:</p>
+where "&lt;revision&gt;" is the minimum revision at which the library is available. For example:</p>
 
 <pre>
-com.android.support:mediarouter-v7:18.0.+
+com.android.support:mediarouter-v7:21.0.+
 </pre>
 
 <p class="caution">The v7 mediarouter library APIs introduced in Support Library
diff --git a/docs/html/training/articles/wear-location-detection.jd b/docs/html/training/articles/wear-location-detection.jd
new file mode 100644
index 0000000..b0d9755
--- /dev/null
+++ b/docs/html/training/articles/wear-location-detection.jd
@@ -0,0 +1,375 @@
+page.title=Detecting Location on Android Wear
+page.tags="gps"
+
+page.article=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>In this document</h2>
+<ol class="nolist">
+  <li><a href="#Connect">Connect to Google Play Services</a></li>
+  <li><a href="#Request">Request Location Updates</a></li>
+  <li><a href="#DetectGPS">Detect On-Board GPS</a></li>
+  <li><a href="#Disconnection">Handle Disconnection Events</a></li>
+  <li><a href="#Notify">Handle Location Not Found</a></li>
+  <li><a href="#Synchronize">Synchronize Data</a></li>
+</ol>
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+  <li>Android 4.3 (API Level 18) or higher on the handset device</li>
+  <li><a href="{@docRoot}google/play-services/index.html">Google Play services</a> 6.1 or higher</li>
+  <li>An Android Wear device</li>
+</ul>
+<h2>See also</h2>
+<ul>
+  <li><a href="{@docRoot}training/location/index.html">Making Your App Location-Aware
+  </a></li>
+</ul>
+</div></div>
+
+<p>Location awareness on wearable devices enables you to create apps that give users a better
+understanding of their geographic position, movement and what's around them. With the small form
+factor and glanceable nature of a wearable device, you can build low-friction apps that record and
+respond to location data.</p>
+
+<p>Some wearable devices include a GPS sensor that can retrieve location data without another
+tethered device. However, when you request location data in a wearable app, you don't have to worry
+about where the location data originates; the system retrieves the location updates using the most
+power-efficient method. Your app should be able to handle loss of location data, in case the wear
+device loses connection with its paired device and does not have a built-in GPS sensor.</p>
+
+<p>This document shows you how to check for on-device location sensors, receive location data, and
+monitor tethered data connections.</p>
+
+<p class="note"><b>Note:</b> The article assumes that you know how to use the Google Play services
+API to retrieve location data. For more information, see <a href="{@docRoot}training/
+location/index.html">Making Your App Location-Aware</a>.</p>
+
+<h2 id="Connect">Connect to Google Play Services</h2>
+
+<p>Location data on wearable devices is obtained though the Google Play services location APIs. You
+use the <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">
+<code>FusedLocationProviderApi</code></a> and its accompanying classes to obtain this data.
+To access location services, create an instance of
+<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">
+<code>GoogleApiClient</code></a>, which is
+the main entry point for any of the Google Play services APIs.
+</p>
+
+<p class="caution"><b>Caution:</b> Do not use the existing <a href="{@docRoot}reference/android/location/package-summary.html">Location</a>
+APIs in the Android framework. The best practice for retrieving location updates is through the
+Google Play services API as outlined in this article.</p>
+
+<p>To connect to Google Play services, configure your app to create an instance of
+<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">
+<code>GoogleApiClient</code></a>:</p>
+
+<ol>
+  <li>Create an activity that specifies an implementation for the interfaces <a
+href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html"
+>{@code ConnectionCallbacks}</a>, <a href="{@docRoot}reference/com/google/android/gms/common/api/
+GoogleApiClient.OnConnectionFailedListener.html">{@code OnConnectionFailedListener}</a>, and <a
+href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code
+LocationListener}</a>.</li>
+  <li>In your activity's {@link android.app.Activity#onCreate onCreate()} method, create an instance
+of <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>
+GoogleApiClient</code></a> and add the Location service.
+  </li>
+  <li>To gracefully manage the lifecycle of the connection, call  <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
+  {@code connect()}</a> in the {@link android.app.Activity#onResume onResume()} method and
+  <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#disconnect()">
+  {@code disconnect()}</a> in the {@link android.app.Activity#onPause onPause()} method.
+  </li>
+</ol>
+
+<p>The following code example shows an implementation of an activity that implements the
+<a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">
+{@code LocationListener}</a> interface:</p>
+
+<pre>
+public class WearableMainActivity extends Activity implements
+    GoogleApiClient.ConnectionCallbacks,
+    GoogleApiClient.OnConnectionFailedListener,
+    LocationListener {
+
+    private GoogleApiClient mGoogleApiClient;
+    ...
+
+    &#64;Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ...
+        mGoogleApiClient = new GoogleApiClient.Builder(this)
+                .addApi(LocationServices.API)
+                .addApi(Wearable.API)  // used for data layer API
+                .addConnectionCallbacks(this)
+                .addOnConnectionFailedListener(this)
+                .build();
+    }
+
+    &#64;Override
+    protected void onResume() {
+        super.onResume();
+        mGoogleApiClient.connect();
+        ...
+    }
+
+    &#64;Override
+    protected void onPause() {
+        super.onPause();
+        ...
+        mGoogleApiClient.disconnect();
+    }
+}
+</pre>
+
+<p>For more information on connecting to Google Play services, see <a href="{@docRoot}google/auth
+/api-client.html">Accessing Google APIs</a>.</p>
+
+<h2 id="Request">Request Location Updates</h2>
+
+<p>After your app has connected to the Google Play services API, it is ready to start receiving
+location updates. When the system invokes the
+<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">
+<code>onConnected()</code></a> callback for your client, you build the location data request as
+follows:</p>
+
+<ol>
+  <li>Create a <a
+href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html"
+>{@code LocationRequest}</a> object and set any options using methods like <a
+href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setPriority(int)"
+>{@code setPriority()}</a>.
+  </li>
+  <li>Request location updates using <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">
+  <code>requestLocationUpdates()</code></a>.
+  </li>
+  <li>Remove location updates using <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#removeLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationListener)">
+  <code>removeLocationUpdates()</code></a> in the {@link android.app.Activity#onPause
+  onPause()} method.
+  </li>
+</ol>
+
+<p>The following example shows how to retrieve and remove location updates:</p>
+
+<pre>
+&#64;Override
+public void onConnected(Bundle bundle) {
+    LocationRequest locationRequest = LocationRequest.create()
+            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
+            .setInterval(UPDATE_INTERVAL_MS)
+            .setFastestInterval(FASTEST_INTERVAL_MS);
+
+    LocationServices.FusedLocationApi
+            .requestLocationUpdates(mGoogleApiClient, locationRequest, this)
+            .setResultCallback(new ResultCallback<Status>() {
+
+                &#64;Override
+                public void onResult(Status status) {
+                    if (status.getStatus().isSuccess()) {
+                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                            Log.d(TAG, "Successfully requested location updates");
+                        }
+                    } else {
+                        Log.e(TAG,
+                                "Failed in requesting location updates, "
+                                        + "status code: "
+                                        + status.getStatusCode()
+                                        + ", message: "
+                                        + status.getStatusMessage());
+                    }
+                }
+            });
+}
+
+&#64;Override
+protected void onPause() {
+    super.onPause();
+    if (mGoogleApiClient.isConnected()) {
+        LocationServices.FusedLocationApi
+             .removeLocationUpdates(mGoogleApiClient, this);
+    }
+    mGoogleApiClient.disconnect();
+}
+
+&#64;Override
+public void onConnectionSuspended(int i) {
+    if (Log.isLoggable(TAG, Log.DEBUG)) {
+        Log.d(TAG, "connection to location client suspended");
+    }
+}
+
+</pre>
+
+<p>Now that you have enabled location updates, the system calls the {@link android.location.LocationListener#onLocationChanged
+onLocationChanged()} method with the updated location at the interval specified in <a
+href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">
+{@code setInterval()}</a>
+</p>
+
+<h2 id="DetectGPS">Detect On-Board GPS</h2>
+
+<p>Not all wearables have a GPS sensor. If your user goes out for a run and leaves their phone at
+home, your wearable app cannot receive location data through a tethered connection. If the
+wearable device does not have a sensor, you should detect this situation and warn the user that
+location functionality is not available.
+
+<p>To determine whether your Android Wear device has a built-in GPS sensor, use the
+{@link android.content.pm.PackageManager#hasSystemFeature hasSystemFeature()}
+method. The following code detects whether the device has built-in GPS when you start an activity:
+</p>
+
+<pre>
+
+protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+
+    setContentView(R.layout.main_activity);
+    if (!hasGps()) {
+        Log.d(TAG, "This hardware doesn't have GPS.");
+        // Fall back to functionality that does not use location or
+        // warn the user that location function is not available.
+    }
+
+    ...
+}
+
+private boolean hasGps() {
+    return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS);
+}
+</pre>
+
+<h2 id="Disconnection">Handle Disconnection Events</h2>
+
+<p>Wearable devices relying on a tethered connection for location data may lose their connections
+abruptly. If your wearable app expects a constant stream of data, you must handle the
+disconnection based upon where that data is interrupted or unavailable. On a wearable device with no
+onboard GPS sensor, loss of location data occurs when the device loses its tethered data connection.
+</p>
+
+<p>In cases where your app depends on a tethered data connection for location data and the wear
+device does not have a GPS sensor, you should detect the loss of that connection, warn the user, and
+gracefully degrade the functionality of your app.</p>
+
+<p>To detect the loss of a tethered data connection:</p>
+
+<ol>
+  <li>Extend a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
+  <code>WearableListenerService</code></a> that lets you listen for important data layer events.
+  </li>
+  <li>Declare an intent filter in your Android manifest to notify the system about your
+  <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>
+  WearableListenerService</code></a>.
+  This filter allows the system to bind your service as needed.
+<pre>
+&lt;service android:name=".NodeListenerService"&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name="com.google.android.gms.wearable.BIND_LISTENER" /&gt;
+    &lt;/intent-filter&gt;
+&lt;/service>
+</pre>
+  </li>
+  <li>Implement the <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onPeerDisconnected(com.google.android.gms.wearable.Node)">
+  <code>onPeerDisconnected()</code></a> method and handle cases of whether or not the device has
+  built-in
+  GPS.
+<pre>
+public class NodeListenerService extends WearableListenerService {
+
+    private static final String TAG = "NodeListenerService";
+
+    &#64;Override
+    public void onPeerDisconnected(Node peer) {
+        Log.d(TAG, "You have been disconnected.");
+        if(!hasGPS()) {
+            // Notify user to bring tethered handset
+            // Fall back to functionality that does not use location
+        }
+    }
+    ...
+}
+</pre>
+  </li>
+</ol>
+
+For more information, read the <a href="{@docRoot}training/wearables/data-layer/events.html#Listen">
+Listen for Data Layer Events</a> guide.
+
+<h2 id="Notify">Handle Location Not Found</h2>
+
+<p>When the GPS signal is lost, you can still retrieve the last known location using
+<a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">
+<code>getLastLocation()</code></a>. This method can be helpful in situations where you are unable to
+get a GPS fix, or when your wearable doesn't have built-in GPS and loses its connection with the
+phone.</p>
+
+<p>The following code uses <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">
+<code>getLastLocation()</code></a> to retrieve the last known location if available:
+</p>
+
+<pre>
+Location location = LocationServices.FusedLocationApi
+                .getLastLocation(mGoogleApiClient);
+</pre>
+
+<h2 id="Synchronize">Synchronize Data</h2>
+
+<p>If your wearable app records data using the built-in GPS, you may want to synchronize
+the location data with the handset. With the {@link android.location.LocationListener}, you
+implement the {@link android.location.LocationListener#onLocationChanged onLocationChanged()}
+method to detect and record the location as it changes.
+
+<p>The following code for wearable apps detects when the location changes and uses the data layer
+API to store the data for later retrieval by your phone app:</p>
+
+<pre>
+&#64;Override
+public void onLocationChanged(Location location) {
+    ...
+    addLocationEntry(location.getLatitude(), location.getLongitude());
+
+}
+
+private void addLocationEntry(double latitude, double longitude) {
+    if (!mSaveGpsLocation || !mGoogleApiClient.isConnected()) {
+        return;
+    }
+
+    mCalendar.setTimeInMillis(System.currentTimeMillis());
+
+    // Set the path of the data map
+    String path = Constants.PATH + "/" + mCalendar.getTimeInMillis();
+    PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(path);
+
+    // Set the location values in the data map
+    putDataMapRequest.getDataMap()
+            .putDouble(Constants.KEY_LATITUDE, latitude);
+    putDataMapRequest.getDataMap()
+            .putDouble(Constants.KEY_LONGITUDE, longitude);
+    putDataMapRequest.getDataMap()
+            .putLong(Constants.KEY_TIME, mCalendar.getTimeInMillis());
+
+    // Prepare the data map for the request
+    PutDataRequest request = putDataMapRequest.asPutDataRequest();
+
+    // Request the system to create the data item
+    Wearable.DataApi.putDataItem(mGoogleApiClient, request)
+            .setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
+                &#64;Override
+                public void onResult(DataApi.DataItemResult dataItemResult) {
+                    if (!dataItemResult.getStatus().isSuccess()) {
+                        Log.e(TAG, "Failed to set the data, "
+                                + "status: " + dataItemResult.getStatus()
+                                .getStatusCode());
+                    }
+                }
+            });
+}
+</pre>
+
+<p>For more information on how to use the Data Layer API, see the <a href="{@docRoot}training/
+wearables/data-layer/index.html">Sending and Syncing Data</a>
+guide.</p>
diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
index 179b3ac..c082642 100644
--- a/docs/html/training/basics/firstapp/building-ui.jd
+++ b/docs/html/training/basics/firstapp/building-ui.jd
@@ -1,12 +1,8 @@
 page.title=Building a Simple User Interface
-parent.title=Building Your First App
-parent.link=index.html
-
 trainingnavtop=true
-previous.title=Running Your App
-previous.link=running-app.html
-next.title=Starting Another Activity
-next.link=starting-activity.html
+
+page.tags=ui, views, layouts, widgets, string resources
+helpoutsWidget=true
 
 @jd:body
 
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index c4cb362..418eb68 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -1,6 +1,7 @@
 page.title=Creating an Android Project
-parent.title=Building Your First App
-parent.link=index.html
+
+page.tags=eclipse adt, sdk tools, project setup
+helpoutsWidget=true
 
 trainingnavtop=true
 next.title=Running Your App
diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd
index 1b49096..ac8e64a 100644
--- a/docs/html/training/basics/firstapp/index.jd
+++ b/docs/html/training/basics/firstapp/index.jd
@@ -3,8 +3,9 @@
 
 trainingnavtop=true
 startpage=true
-next.title=Creating an Android Project
-next.link=creating-project.html
+
+page.tags=sdk tools
+helpoutsWidget=true
 
 @jd:body
 
@@ -47,6 +48,3 @@
 <p>This class uses a tutorial format that incrementally builds a small Android app that teaches
 you some fundamental concepts about Android development, so it's important that you follow each
 step.</p>
-
-<p><strong><a href="creating-project.html">Start the first lesson &rsaquo;</a></strong></p>
-
diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd
index 23cedba..96b7172 100644
--- a/docs/html/training/basics/firstapp/running-app.jd
+++ b/docs/html/training/basics/firstapp/running-app.jd
@@ -3,10 +3,9 @@
 parent.link=index.html
 
 trainingnavtop=true
-previous.title=Creating a Project
-previous.link=creating-project.html
-next.title=Building a Simple User Interface
-next.link=building-ui.html
+
+page.tags=emulator
+helpoutsWidget=true
 
 @jd:body
 
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 27d2c10..f9dcba4 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -3,8 +3,9 @@
 parent.link=index.html
 
 trainingnavtop=true
-previous.title=Building a Simpler User Interface
-previous.link=building-ui.html
+
+page.tags=input events, intents, activity lifecycle
+helpoutsWidget=true
 
 @jd:body
 
diff --git a/docs/html/training/material/compatibility.jd b/docs/html/training/material/compatibility.jd
index 5e03450..49ef7f7 100644
--- a/docs/html/training/material/compatibility.jd
+++ b/docs/html/training/material/compatibility.jd
@@ -131,9 +131,9 @@
 
 <pre>
 dependencies {
-    compile 'com.android.support:appcompat-v7:+'
-    compile 'com.android.support:cardview-v7:+'
-    compile 'com.android.support:recyclerview-v7:+'
+    compile 'com.android.support:appcompat-v7:21.0.+'
+    compile 'com.android.support:cardview-v7:21.0.+'
+    compile 'com.android.support:recyclerview-v7:21.0.+'
 }
 </pre>
 
diff --git a/docs/html/training/material/drawables.jd b/docs/html/training/material/drawables.jd
index 8d7f453..fd21e3d 100644
--- a/docs/html/training/material/drawables.jd
+++ b/docs/html/training/material/drawables.jd
@@ -73,7 +73,7 @@
 <pre>
 dependencies {
     ...
-    compile 'com.android.support:palette-v7:+'
+    compile 'com.android.support:palette-v7:21.0.+'
 }
 </pre>
 
diff --git a/docs/html/training/material/lists-cards.jd b/docs/html/training/material/lists-cards.jd
index eb45f0d..e7bdfe0 100644
--- a/docs/html/training/material/lists-cards.jd
+++ b/docs/html/training/material/lists-cards.jd
@@ -260,7 +260,7 @@
 <pre>
 dependencies {
     ...
-    compile 'com.android.support:cardview-v7:+'
-    compile 'com.android.support:recyclerview-v7:+'
+    compile 'com.android.support:cardview-v7:21.0.+'
+    compile 'com.android.support:recyclerview-v7:21.0.+'
 }
 </pre>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 0fee771..9f06666 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -834,6 +834,12 @@
           </li>
         </ul>
       </li>
+      <li>
+        <a href="<?cs var:toroot ?>training/articles/wear-location-detection.html"
+           description=
+           "How to detect location data on Android Wear devices."
+          >Detecting Location</a>
+      </li>
     </ul>
   </li>
   <!-- End Building for wearables -->
diff --git a/docs/html/training/tv/games/index.jd b/docs/html/training/tv/games/index.jd
index 29b055b..2f510a9 100644
--- a/docs/html/training/tv/games/index.jd
+++ b/docs/html/training/tv/games/index.jd
@@ -31,7 +31,7 @@
 </p>
 
 
-<h3 id="shared-display">Shared display</h3>
+<h3 id="shared-display">Consider the shared display</h3>
 
 <p>
   A living-room TV poses design challenges for multiplayer games, in that all players can see
@@ -57,7 +57,7 @@
 </ul>
 
 
-<h3 id="landscape-display">Landscape display</h3>
+<h3 id="landscape-display">Support landscape display</h3>
 
 <p>
   A TV is always sideways: You can’t turn it, and there is no portrait orientation. Always design
@@ -69,19 +69,19 @@
 
 <p>
   TVs don't have touch interfaces, so it's even more important to get your controls right and make
-  sure that players find them intuitive and fun to use. The separation of controller from device
-  also introduces some other issues to pay attention to, like keeping track of multiple players'
+  sure players find them intuitive and fun to use. Handling controllers
+  also introduces some other issues to pay attention to, like keeping track of multiple
   controllers, and handling disconnects gracefully.
 </p>
 
-<h3 id="d-pad">D-pad</h3>
+<h3 id="d-pad">Support D-pad controls</h3>
 
 <p>
   Plan your control scheme around a directional pad (D-pad) control, since this control set is the
   default for Android TV devices. The player needs to be able to use a D-Pad in all aspects of the
-  game–not just controlling core gameplay, but also navigating menus and ads. For this reason, you
-  should also ensure that your Android TV game does not refer to a touch interface: For example, an
-  Android TV game should not tell a player to <strong>Tap here to skip</strong>.
+  game&mdash;not just controlling core gameplay, but also navigating menus and ads. For this reason, you
+  should also ensure that your Android TV game does not refer to a touch interface. For example, an
+  Android TV game should not tell a player to "<em>Tap</em> here to continue."
 </p>
 
 <p>
@@ -91,35 +91,35 @@
 
 <ul>
   <li>
-    <strong>Communicate Controller Requirements up Front</strong> - Use your Play Store description
+    <strong>Communicate Controller Requirements up Front</strong>. Use your Google Play description
     to communicate to the player any expectations about controllers. If a game is better suited to
     a gamepad with a joystick than one with only a D-pad, make this fact clear. A player who uses
-    an ill-suited controller for a game is likely to have a subpar experience–and penalize your
+    an ill-suited controller for a game is likely to have a subpar experience and penalize your
     game in the ratings.
   </li>
   <li>
-    <strong>Use Consistent Button Mapping</strong> - Intuitive and flexible button mapping is key
-    to a good user experience. For example, you can adhere to accepted custom by using the A button
-    to <code>Accept</code>, and the B button to <code>Cancel</code>. You can also offer flexibility
-    in the form of remappability. For more information on button mapping, see <a href=
+    <strong>Use Consistent Button Mapping</strong>. Intuitive and flexible button mapping is key
+    to a good user experience. For example, you should adhere to accepted customs by using the A button
+    to <em>Accept</em>, and the B button to <em>Cancel</em>. You can also offer flexibility
+    in the form of remappability. For more information about button mapping, see <a href=
     "http://developer.android.com/training/game-controllers/controller-input.html">Handling
     Controller Actions</a>.
   </li>
   <li>
-    <strong>Detect Controller Capabilities and Adjust Accordingly</strong> - Query the controller
+    <strong>Detect Controller Capabilities and Adjust Accordingly</strong>. Query the controller
     about its capabilities in order to optimize the match between controller and game. For example,
     you may intend for a player to steer an object by waving the controller in the air. If a
     player's controller lacks accelerometer and gyroscope hardware, however, waving will not work.
-    When, however, your game queries the controller and discovers that motion detection is not
-    supported, it can switch over to an alternative, available control scheme. For more information
-    on querying controller capabilities, see <a href=
+    So, your game should query the controller and if motion detection is not
+    supported, switch over to an alternative, available control scheme. For more information
+    about querying controller capabilities, see <a href=
     "http://developer.android.com/training/game-controllers/compatibility.html">Supporting
     Controllers Across Android Versions</a>.
   </li>
 </ul>
 
 
-<h3 id="back-button">Back-button behavior</h3>
+<h3 id="back-button">Provide appropriate Back-button behavior</h3>
 
 <p>
   The Back button should never act as a toggle. For example, do not use it to both open and close a
@@ -139,18 +139,18 @@
 </p>
 
 
-<h3 id="multiple-controllers">Handling multiple controllers</h3>
+<h3 id="multiple-controllers">Handle multiple controllers</h3>
 
 <p>
   When multiple players are playing a game, each with his or her own controller, it is important to
-  map each player-controller pair. For information on how to implement controller-number
+  map each player-controller pair. For information about how to implement controller-number
   identification, see <a href=
   "http://developer.android.com/reference/android/view/InputDevice.html#getControllerNumber">Input
   Devices</a>.
 </p>
 
 
-<h3 id="handle-disconnect">Handling disconnects</h3>
+<h3 id="handle-disconnect">Handle controller disconnects</h3>
 
 <p>
   When a controller is disconnected in the middle of gameplay, the game should pause, and a dialog
@@ -159,7 +159,7 @@
 
 <p>
   The dialog should also offer troubleshooting tips (for example, a pop-up dialog telling the
-  player to "Check your Bluetooth connection"). For more information on implementing input-device
+  player to "Check your Bluetooth connection"). For more information about implementing input-device
   support, see <a href=
   "http://developer.android.com/training/game-controllers/controller-input.html">Handling Controller
   Actions</a>. Specific information about Bluetooth connections is at <a href=
@@ -167,25 +167,53 @@
 </p>
 
 
+<h3 id="ControllerHelp">Show controller instructions</h3>
+
+<p>If your game provides visual game control instructions, the
+controller image should be free of branding and include only <a
+href="{@docRoot}training/game-controllers/controller-input.html#button"
+>buttons compatible with Android</a>.</p>
+
+<p>For sample images of an Android-compatible controller, download the
+<a href="http://storage.googleapis.com/androiddevelopers/design/android_tv_gamepad_template-2014-10.zip"
+>Android TV Gamepad Template (ZIP)</a>.
+It includes a white controller on black background and a black controller on white background
+(shown in figure 1), as a PNG file and an Adobe&reg; Illustrator&reg; file.</p>
+
+<img src="{@docRoot}images/games/game-controller-buttons_2x.png" width="700"
+     srcset="{@docRoot}images/games/game-controller-buttons_2x.png 2x,
+             {@docRoot}images/games/game-controller-buttons.png 1x" />
+<p class="img-caption"><b>Figure 1.</b> Example controller instructions using the
+<a href="http://storage.googleapis.com/androiddevelopers/design/android_tv_gamepad_template-2014-10.zip"
+>Android TV Gamepad Template (ZIP)</a>.
+
+
+
+
 <h2 id="manifest">Manifest</h2>
 
+<p>There are a some special things games should include in the Android manifest.</p>
+
+<h3 id="Launcher">Show your game in the launcher</h3>
 <p>
-  The Android TV launcher home screen displays games in a separate row from regular apps. The TV
-  framework uses the <code>android:isGame</code> manifest attribute to differentiate games from
-  non-game apps. Set this value to <code>true</code> in your game's app manifest, as shown in the
-  following code example:
+  The Android TV launcher home screen displays games in a separate row from regular apps.
+  To make your game appear in the list of games, add the
+  <a href="{@docRoot}guide/topics/manifest/meta-data-element.html"
+  ><code>&lt;meta-data></code></a> tag in your app manifest with <code>android:name</code>
+  set to <code>"isGame"</code> and <code>android:value</code>
+  set to <code>"true"</code>. For example:
 </p>
 
 <pre class="fragment">
 &lt;application&gt;
   ...
-  &lt; meta-data android:name="isGame" android:value="true" &gt;
+  &lt;meta-data android:name="isGame" android:value="true" &gt;
   ...
 &lt;/application&gt;
 </pre>
 
 
-<h3 id="gamepad">Game Controllers</h3>
+<h3 id="gamepad">Declare support for game controllers</h3>
 
 <p>
   Games controllers may not be available or active for users of a TV device. In order to properly
@@ -215,7 +243,9 @@
 <h2 id="gpgs">Google Play Game Services</h2>
 
 <p>
-  If your game integrates Google Play Game Services, you should keep in mind a number of
+  If your game integrates <a
+  href="https://developers.google.com/games/services/">Google Play Game services</a>,
+  you should keep in mind a number of
   considerations pertaining to achievements, sign-in, saving games, and multiplayer play.
 </p>
 
@@ -224,7 +254,7 @@
 
 <p>
   Your game should include at least five (earnable) achievements. Only a user controlling gameplay
-  from a supported input device should be able to earn achievements. For more information on
+  from a supported input device should be able to earn achievements. For more information about
   achievements and how to implement them, see <a href=
   "https://developers.google.com/games/services/android/achievements">Achievements in Android</a>.
 </p>
@@ -262,7 +292,7 @@
 
 <p>
   A game offering a multiplayer experience must allow at least two players to enter a room. For
-  further information on multiplayer games in Android, see the <a href=
+  further information about multiplayer games in Android, see the <a href=
   "https://developers.google.com/games/services/android/realtimeMultiplayer">Real-time
   Multiplayer</a> and <a href="">Turn-based Multiplayer</a> documentation on the Android developer
   site.
diff --git a/docs/html/training/wearables/apps/index.jd b/docs/html/training/wearables/apps/index.jd
index 7d961b7..ffb4131 100644
--- a/docs/html/training/wearables/apps/index.jd
+++ b/docs/html/training/wearables/apps/index.jd
@@ -1,5 +1,6 @@
 page.title=Creating Wearable Apps
-page.image=wear/images/notifications.png
+page.tags="wear","wearable","app"
+page.image=wear/images/02_notifications.png
 
 @jd:body
 
diff --git a/docs/html/training/wearables/notifications/index.jd b/docs/html/training/wearables/notifications/index.jd
index 17f3cb3..a7b6733 100644
--- a/docs/html/training/wearables/notifications/index.jd
+++ b/docs/html/training/wearables/notifications/index.jd
@@ -1,4 +1,6 @@
 page.title=Adding Wearable Features to Notifications
+page.tags="wear","notifications","wearables"
+page.image=wear/images/01_notifications.png
 @jd:body
 
 <div id="tb-wrapper">
diff --git a/docs/html/training/wearables/notifications/stacks.jd b/docs/html/training/wearables/notifications/stacks.jd
index e71e74c..9a528a4 100644
--- a/docs/html/training/wearables/notifications/stacks.jd
+++ b/docs/html/training/wearables/notifications/stacks.jd
@@ -45,7 +45,7 @@
 Notification notif = new NotificationCompat.Builder(mContext)
          .setContentTitle("New mail from " + sender1)
          .setContentText(subject1)
-         .setSmallIcon(R.drawable.new_mail);
+         .setSmallIcon(R.drawable.new_mail)
          .setGroup(GROUP_KEY_EMAILS)
          .build();
 
@@ -65,7 +65,7 @@
 Notification notif2 = new NotificationCompat.Builder(mContext)
          .setContentTitle("New mail from " + sender2)
          .setContentText(subject2)
-         .setSmallIcon(R.drawable.new_mail);
+         .setSmallIcon(R.drawable.new_mail)
          .setGroup(GROUP_KEY_EMAILS)
          .build();
 
diff --git a/docs/image_sources/distribute/gp-wear-quality.svg b/docs/image_sources/distribute/gp-wear-quality.svg
new file mode 100644
index 0000000..2acf81a
--- /dev/null
+++ b/docs/image_sources/distribute/gp-wear-quality.svg
@@ -0,0 +1,2268 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="2824.887"
+   height="1419.8136"
+   id="svg3004"
+   xml:space="preserve"
+   inkscape:version="0.48.1 "
+   sodipodi:docname="wear_app_quality.svg"><sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1280"
+     inkscape:window-height="1002"
+     id="namedview125"
+     showgrid="false"
+     inkscape:zoom="0.23675905"
+     inkscape:cx="1735.4152"
+     inkscape:cy="-51.97425"
+     inkscape:window-x="1272"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer8"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     fit-margin-top="50"
+     fit-margin-left="200"
+     fit-margin-right="200"
+     fit-margin-bottom="200"><sodipodi:guide
+       orientation="0,1"
+       position="1543.7834,1150.3523"
+       id="guide3963" /><sodipodi:guide
+       orientation="0,1"
+       position="1978.6428,757.82274"
+       id="guide9681" /></sodipodi:namedview><metadata
+     id="metadata3010"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+     id="defs3008"><clipPath
+       id="clipPath3020"><path
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         id="path3022"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3044"><path
+         d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z"
+         id="path3046"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3060"><path
+         d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z"
+         id="path3062"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3086"><path
+         d="m 1058,722 374,0 0,-374 -374,0 0,374 z"
+         id="path3088"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3100"><path
+         d="m 1029,344 432,0 0,-32 -432,0 0,32 z"
+         id="path3102"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3116"><path
+         d="m 1029,756 432,0 0,-32 -432,0 0,32 z"
+         id="path3118"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3060-8"><path
+         d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z"
+         id="path3062-8"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3044-8"><path
+         d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z"
+         id="path3046-8"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3116-3"><path
+         d="m 1029,756 432,0 0,-32 -432,0 0,32 z"
+         id="path3118-0"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3100-0"><path
+         d="m 1029,344 432,0 0,-32 -432,0 0,32 z"
+         id="path3102-0"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3086-0"><path
+         d="m 1058,722 374,0 0,-374 -374,0 0,374 z"
+         id="path3088-4"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3086-0-0"><path
+         d="m 1058,722 374,0 0,-374 -374,0 0,374 z"
+         id="path3088-4-2"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3100-0-7"><path
+         d="m 1029,344 432,0 0,-32 -432,0 0,32 z"
+         id="path3102-0-2"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3116-3-2"><path
+         d="m 1029,756 432,0 0,-32 -432,0 0,32 z"
+         id="path3118-0-6"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3060-8-2"><path
+         d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z"
+         id="path3062-8-4"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3044-8-3"><path
+         d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z"
+         id="path3046-8-8"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3086-4"><path
+         inkscape:connector-curvature="0"
+         d="m 1058,722 374,0 0,-374 -374,0 0,374 z"
+         id="path3088-8" /></clipPath><clipPath
+       id="clipPath3100-8"><path
+         inkscape:connector-curvature="0"
+         d="m 1029,344 432,0 0,-32 -432,0 0,32 z"
+         id="path3102-2" /></clipPath><clipPath
+       id="clipPath3116-4"><path
+         inkscape:connector-curvature="0"
+         d="m 1029,756 432,0 0,-32 -432,0 0,32 z"
+         id="path3118-5" /></clipPath><clipPath
+       id="clipPath3044-8-1"><path
+         inkscape:connector-curvature="0"
+         d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z"
+         id="path3046-8-5" /></clipPath><clipPath
+       id="clipPath3060-8-27"><path
+         inkscape:connector-curvature="0"
+         d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z"
+         id="path3062-8-6" /></clipPath><clipPath
+       id="clipPath3086-0-0-4"><path
+         inkscape:connector-curvature="0"
+         d="m 1058,722 374,0 0,-374 -374,0 0,374 z"
+         id="path3088-4-2-1" /></clipPath><clipPath
+       id="clipPath3100-0-7-1"><path
+         inkscape:connector-curvature="0"
+         d="m 1029,344 432,0 0,-32 -432,0 0,32 z"
+         id="path3102-0-2-5" /></clipPath><clipPath
+       id="clipPath3116-3-2-9"><path
+         inkscape:connector-curvature="0"
+         d="m 1029,756 432,0 0,-32 -432,0 0,32 z"
+         id="path3118-0-6-5" /></clipPath><clipPath
+       id="clipPath3044-8-3-2"><path
+         inkscape:connector-curvature="0"
+         d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z"
+         id="path3046-8-8-2" /></clipPath><clipPath
+       id="clipPath3060-8-2-1"><path
+         inkscape:connector-curvature="0"
+         d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z"
+         id="path3062-8-4-5" /></clipPath><clipPath
+       id="clipPath3942"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3944"
+         d="m 1337.7,554.569 67.31,0 0,-64.569 -67.31,0 0,64.569 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3912"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3914"
+         d="m 1404.777,549.002 12,0 0,11.998 -12,0 0,-11.998 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3908"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3910"
+         d="m 1404.78,561 12,0 0,-12 -12,0 0,12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3886"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3888"
+         d="m 1363,547.865 32,0 0,12 -32,0 0,-12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3882"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3884"
+         d="m 1363,559.865 32,0 0,-12.002 -32,0 0,12.002 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3852"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3854"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAAAAACTooUSAAAAAXNCSVQI5gpbmQAAAXhJREFUWIXt2T9v3DAMBfBHWj4Fzh2CXjsEaZd+/+8VZGiN+v4Y1cni6+ADmqUjnQ7kqEE/ULQXPgEAQLBB8S8lAnE3SZCrKFBVVd8+CTMzA5EAaOr7PrmShC211sWABNGUh8fHnNRTtKVcrzMWY4JoPxw/Hw+585sl2cp5/AkzMgm033/59nIcevUCAavz+Cq3Upvce3z5/nzY+T0r7XZ+w/zrpMJ1jvvj89enB0/x94Rpn5PK/VvNw+HpU+78xFZwGnJSAAkQ0a7f5fzgKSLv+k5FgAQAoqJd1zmK6DqVdWppPZK1vES8u93xj/hHhRhiiCGGGGKIIYYYYoghhhhiiCGGGOL/Jt73ciRJuinvr08AQKO11vzCALbWjMa7SFqrt1LgutEtt9qMXHu0pcznCc5b6/NcFgOQQFvKZXzDyXszP17KYkQCrc7jKyb/9GGcqxGJYvXyg9ctEpZLNXDtEWXaJEWqRgggWyZl/IA08EMST2DTVPcPY4fdi0eNNAgAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3840"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3842"><g
+           id="g3844"
+           clip-path="url(#clipPath3836)"><g
+             id="g3846"><g
+               id="g3848"
+               transform="matrix(113,0,0,68,1351,505)"><image
+                 id="image3850"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAYAAAC2ydrOAAAABHNCSVQICAgIfAhkiAAAA1NJREFUeJztnc1uozAURj8HjCMCikq7iNJu+v7vVXXRovJn1RDiWUztMQnttIuQmat7pKugAFn4yDZk8V0BwGIGIcTc18wVsXZWFQROJAohvMDwmLke1lovMDx2xO7AyVqtVmcVnmeWw8k6Ho9nFZ6Pw5tWqxXiOIaU0lccxyzyCoQCD4cDhmHwdTgcvEjgQ6IQwgtUSiFNU2w2G2w2GyilvEiWuBzWWi/QGIOu69B1HbTWAOBFWmunEqWUSNMURVHg9vYWRVEgz3MopRBFEe+RC+H2vXEcYYxB0zQoyxKvr68A/iyv7ro43AullMiyDHd3d3h4eMB+v0dRFEjTFFJKv6wyl+d4PGIYBmitUZYlnp6eIIRA3/cwxmAYBozjCCHE5zNxv9/j8fERu90OeZ4jSRJeUhfCLaV936NpGjw/PwMAtNZ4e3tDXdfexdly6vbELMtQFAV2ux3u7++x3W6xXq9Z4kI4ie/v76iqCgBQVRWyLJt9Rpl9OnUPN3meY7vd4ubmZrIvMpcl3A8BoK5rpGk6ERgyeU90MzKKIkgpkSQJlFJQSmG9XrPEhXASAUAphSRJIKVEFEV+BoYe4tMfcCJDoWGxxMvj3hHdmIc+5sb/TKLD2Z4r5vL8ZNz5nYEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEAn2a7uWji02Iuz0/H/kyiC0x1n+M4+gI4kX8JXFSmq9DHnMw4vDEUNwyDz5t24akclbkMYWitMQZ93/vM7zDA3TGZiWGEv9YaTdP4+GKOj16O0/jopmmgtYYx5qwnBvAh8bQHQ9u2KMvSB4jXdc1B7gsyF+ReliXatp2InHSocTedRvgDvwPEuaXC8sz5KMsSWmsMwzCVaK2FEMLf1LYtXl5eYK1F13Xc3OQKfNXcpG1bL9FdOzsTAcAYg6qquM3QlfiqzdDpTPSt98LeGNzw6/p8p+HXrESAW+/9S3y39R43wfwP+FsTzDOJ/gTL++f47K+3XyWNnXDxB1SBAAAAAElFTkSuQmCC"
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3836"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3838"
+         d="m 1351,573 113,0 0,-68 -113,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3832"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3834"
+         d="m 1351,573 113,0 0,-68 -113,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3824"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3826"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3798"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3800"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAAAAACTooUSAAAAAXNCSVQI5gpbmQAAAZ9JREFUWIXt2U9v1DAQBfA348lmyXa1FdBSgRDf/4tVe4CI7J+oXtvzOKQIOCOnF8/Ft/lpZCeHeQIAgGCF4h9KBFLdJEEuokBVVevOSbi7OwiDiIZN14WqJOE5pZQdMEBtO+yGPmhN0XO8Xmdkp4mEfv/+w/2u13p3SZZ4Hn/AnTRo2B6evjwd3lnFGT3N47PcYipiIrY9PH77+nHotBpIv52PmH+eVGiQsBnuHz5/2m1qii8TprveVJa3av2wP9xt6j0dlojT0JsCMJAk1LptVRH9pgsqAhjoJedC0YqfBxGCytLfCJZcsgM1/3Qi8ru7gnQv7mQ17t9SgEutBEIBYEXvVVy1mtjEJjaxiU1sYhOb2MQmNrGJTWxiE5v4P2XLUXlt9Xd7AwA6vZRSLwxgKcXpfBVJL+kWI0LNjW68peLkMqPnOJ8nbCvuV/1lOs8xO5aNbo6X8YhTzR2y387H8RKzEwZ6msdnTDWzgCV9GOfkhFE8Xb7zuu9D9YTlkhxcZkScelshRUpOCCBqXdfZOkkZ3yANfJPEE1g11f0FocoCRBRb0tkAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3786"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3788"><g
+           id="g3790"
+           clip-path="url(#clipPath3782)"><g
+             id="g3792"><g
+               id="g3794"
+               transform="matrix(113,0,0,68,1351,444)"><image
+                 id="image3796"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAYAAAC2ydrOAAAABHNCSVQICAgIfAhkiAAAA59JREFUeJztnclurDoURTdgmkAhSmlLiaL8/49FGSQodFZM5zd4sstUkdsMQnKPzpKsQgVMWDo2ZrCPB0BjBc/z1v5mvhGtV1XBw4lEz/OsQPeY+T601lage2wQ5sDI8n3/bLjnme0wsuZ5PhvueQEcK873fQRBgCiKEIYhwjBEEAQs8htwBY7jiGEY7BjH0YoEnEr0fR9CCCRJgjRNkWUZ0jRFHMdWJEvcDq21FaiUQtd16LoOUkoAsCK11hCmCoMgQBzHyPMcl5eXuLq6wn6/R5ZliOPYSmSRX49Z96ZpglIKTdOgLEu8vb0BOE6v5joBwE6jSZKgKAocDgc8PDzgcDigKApcXFxACMECN2SeZwzDACklyrLE8/MzPM9D3/dQSmEYBkzTBM/zjpVoptKiKHB7e4unpyc8Pj7i+voaaZoiDEO7NjJfi5lK+75H0zR4eXkBAEgp8f7+jrqu7cxoK9FMp1EUIU1T7Pd73Nzc4P7+Hnd3d8iyDFEUscSNMBI/Pj5QVRUAoKoq7HY7xHEMIcTiHeXs7VQIgTiOkaYp8jxHURTY7XZWIk+pX4+7HgJAXdf2JdMIdBHmJncAx7fVMAyRJAlL3BAjEQDiOLZbPneX4HqwEud5xjRNGMcR4zhimiZorRf7R5a4DaaQgiBYPPfPnr9wP+cYiebX3VAC/BluS8yzdsdn+MBxOjX7j2mazvYizM/FrpCn6+LpGsn8XM72DCzv34M3fgRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQQQn53gdKnv42+f/ZlEk/HmJi+aAXAi/xaYsEQzXB9rMoV7oytuGAabN23CU4MgYIkb4IbWKqXQ973N/F4LTVxUohvhL6VE0zQ2vjhJEs473YjT+OimaSClhFJqNcJ0EVprBLZti7IsbYB4XdecPLwha0HuZVmibduFyEWHGnPTaYQ/8H+AOKfxb8+aj7IsIaXEMAxLiSYi2tzUti1eX1+htUbXdcjz3Hap4eThbfhVc5O2ba1Ec+1qJQKAUgpVVa1G+DNfz6/aDJ1Wom2957ZUMM2+wjBcRPizxO34k4ZfqxIBbr33k/jT1nvcBPMf4HdNMM8k2hMs78fx2ae3/wBR6gt9OOvm0AAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3782"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3784"
+         d="m 1351,512 113,0 0,-68 -113,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3778"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3780"
+         d="m 1351,512 113,0 0,-68 -113,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3770"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3772"
+         d="m 1341,490 129,0 0,89 -129,0 0,-89 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3748"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3750"
+         d="m 1214,628 270,0 0,-182 -270,0 0,182 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3726"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3728"
+         d="m 652.002,520.002 12,0 0,11.998 -12,0 0,-11.998 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3722"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3724"
+         d="m 652,532 12.002,0 0,-12 -12.002,0 0,12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3700"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3702"
+         d="m 592,518.865 32,0 0,12 -32,0 0,-12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3696"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3698"
+         d="m 592,530.865 32,0 0,-12.002 -32,0 0,12.002 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3688"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3690"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3662"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3664"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAAAAAAc13L4AAAAAXNCSVQI5gpbmQAAAdJJREFUaIHt2rFu2zAUheFDirICJUZQt0OQdun7v1fgwRHqylJMkbyng1S0He5aarj/C/gDLWnhcQAAONSNfxTOwdXkkCBXjIP33vtqp0OIiAiIAMCHtm1DLQ0hJaWlCBjgfOj6x8cu+EoYKXGe5nsuCHC+7U+fT8euqfLckBKnH+8DKQgOvn368u311Le+ggVg/rie27KkUraTef3+cjzU+Z8kzZcu3caP5NZn5un08vX5oRJmmQ73S39o3PY2df3x+VPXVHlmZAlz3wXvHALgnG/aQ9c9VML4GDxIrt8ZOO980zR1MM47lpyLbBjArVXAAIDkkgvBOq/zP5EiRYTEDjDgGnaBAUgCe8FsGUbLMFqG0TKMlmG0DKNlGC3DaBlGyzBahtEyjJZhtAyjZRgtw2gZRsswWobRMoyWYbQMo2UYLcNoGUZru0r+fWX5//v7lwMAUCillCprHpZShMINQ0pJS4yoc+NfYlxSEXI9GclxHq+osxKh3K/jHLMACKDkeBvO+FlnP0NZxvNwi1mIAEqahzdcay2LJM3D2zAnIQKdpNuFU73NVYnj8H5LAq4ng3ituEbLcZrmJIQDXPWdXk4p5Q2zmwXj3radwF5Wr78ATrQFVxEFtwQAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3650"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3652"><g
+           id="g3654"
+           clip-path="url(#clipPath3646)"><g
+             id="g3656"><g
+               id="g3658"
+               transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"><image
+                 id="image3660"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAABCJJREFUeJzt3UFvskwYheEDAmNQYkq7MLab/v//1bhQUgqMwjDMt3gzBJTmy7Ol50omNSLdcAcfcEEAwGFBEARLb9Mf4dxiFgjwEEwQBGMs09f0Nzjnxlimr73Iv/BhhGH4tKbbaZ18GMMwPK3p9mi6UxiGiKIIcRyPK4oiRrNy01istTDGwBiDrutgrZ1FEwH/QvCxKKWQpil2ux12ux2UUmM0DGadnHNjLG3bQmuNpmmgtcb9fkff97DWAsA8mDiOkaYp8jzH6+sr8jxHlmVQSmGz2XCmWSE/pwzDgLZt0TQNvr+/cb1eURTFbDsARNPZJY5j7Pd7vL294ePjA6fTCXmeI01TxHE8fjXRujjn0Pc9brcbyrLE+XxGHMew1qLrOhhjYK2Ftfb3M8zpdMLn5yeOxyOyLEOSJPxaWqlhGGCMgdYal8sFSikYY1DXNaqqwu12gzEGQRAszzD7/R55nuN4POL9/R2HwwHb7ZbBrNQwDOi6Dk3TIEkS3O93XC4XpGmKJEnGcQT45SrJD75ZluFwOODl5WU2x9B6+Pmk6zpEUQStNdI0fbrYeQrGvxmGITabDeI4RpIkUEpBKYXtdstgVsgHE4Yh2rad3UbxA+/0Bl70+A98NNN4povBrItzbnbMnXOw1qLv+/FyehiG34Px/BlnadF6DcMwhuL/Tn8q4HUyAZjfj/E38fzr6VcSg6HR48zyOL8ADIYWLIXiMRgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBI5NfHEP/fwyJpHaTH+SkY/yha/9daOy4AfG71yvgHm/s1PfZL4UTTHaeRGGPQdR3atkXbtgCAzWbDYFbGB+OPc9d1MMbM4pmGMzvD+Keit20LrTWqqkJZlgCA7XaLMAwZzMr4k8T9fkdZlqiqClprtG2Lvu8xDMPs89F0Jx9LXdcoigLn8xkA8PPzgyRJGMwK+WPfdR2qqsL5fEZRFKjrehaNP8vMgjHGQGuNoijw9fUFACjLEmmaIo5jhCEvqtZo6dgXRQGtNYwx82CccwiCYNyprmtcLhc459A0DbIsg1JqnF94hlkXP6P4OaaqKhRFgev1irqux2D8ZxfPMADQti3KsoRSClEU8etoxR5HkqZp0DTN4hkmAOCAf5fLYRgiiiLEcTwuH4v/DK2Pj8FHY4wZ1+MMMwsGAMIwfFrT7bRO02ge13T7GIw3nVM4s/w90/suS3d9n4IZNzCUP+23nwf+AzNnFIrywW/wAAAAAElFTkSuQmCC"
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3646"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3648"
+         d="m 558.314,543.945 139.351,0 0,-78.634 -139.351,0 0,78.634 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3642"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3644"
+         d="m 558.314,543.945 139.351,0 0,-78.633 -139.351,0 0,78.633 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3634"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3636"
+         d="m 570.26,532 c 0,-30.785 24.955,-55.742 55.74,-55.742 l 0,0 c 30.784,0 55.74,24.957 55.74,55.742 l 0,0 c 0,30.784 -24.956,55.74 -55.74,55.74 l 0,0 c -30.785,0 -55.74,-24.956 -55.74,-55.74"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3610"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3612"
+         d="m 652.333,574.333 101,0 0,-79.333 -101,0 0,79.333 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3592"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3594"
+         d="m 730.778,549 12,0 0,-12 -12,0 0,12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3570"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3572"
+         d="m 679,535.865 32,0 0,12 -32,0 0,-12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3566"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3568"
+         d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3540"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3542"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg=="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3528"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3530"><g
+           id="g3532"
+           clip-path="url(#clipPath3524)"><g
+             id="g3534"><g
+               id="g3536"
+               transform="matrix(93,0,0,68,667,493)"><image
+                 id="image3538"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3524"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3526"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3520"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3522"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3498"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3500"
+         d="m 560,628 270,0 0,-182 -270,0 0,182 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3490"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3492"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3476"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3478"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABHcAAAK/CAAAAADGr34kAAAAAXNCSVQI5gpbmQAACLFJREFUeJzt1DEBACAMwDDAv+fhohwkCnp1zwJIndcBwHd8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4DaBSkuBn0AocgUAAAAAElFTkSuQmCC"
+         height="1"
+         width="1" /></mask><clipPath
+       id="clipPath3470"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3472"
+         d="m 538,215 954,0 0,118 -954,0 0,-118 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3460"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3462"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABHcAAAK/CAAAAADGr34kAAAAAXNCSVQI5gpbmQAACLFJREFUeJzt1DEBACAMwDDAv+fhohwkCnp1zwJIndcBwHd8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4DaBSkuBn0AocgUAAAAAElFTkSuQmCC"
+         height="1"
+         width="1" /></mask><clipPath
+       id="clipPath3454"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3456"
+         d="m 554,720 958,0 0,204 -958,0 0,-204 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3432"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3434"
+         d="m 904,587 32,0 0,12 -32,0 0,-12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3428"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3430"
+         d="m 904,599 32,0 0,-12.002 -32,0 0,12.002 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3420"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3422"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3396"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3398"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAACdCAAAAAAcMECVAAAAAXNCSVQI5gpbmQAAAZdJREFUaIHt27tu20AQheEzy6Vo0BKMKCkMJ03e/70MFzYR3YisljsnBQXETZpg1J0pt/gwGGz7GwAAhtjhX9UMFsmTIFfckFJKKWx7wt3dQWQAKfd9n6N0wpda6+JAhqU8jI+PQ05BuC/lcpmxODMs9eP+6343dCF3J1s5TR9wJ7Mh9dtvP172Y58CbMDrPL3atdRmt81ffj7vNiF3oV9Pb5h/HZNxvfl2//z96SEI/33AYTvkZLffMoy7py9DF4K3guM45AQgA2ap6zfD8BCEY9j0XTIDMgBYstR1XQyOrku2XjivT7ZOAI5PUMz3+8cIFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwv97bkEBSZIR4GcpAwCd3loLaX7YWnM6bzjprV5LQVQhUq61Oblu7kuZTwfEtS2nuSwOIIO+lPP0hmNglTOdy+JEBr3O0ysOoT3RNFcnMs3r+Z2X4BLqXB1cN0c5RDdc1QkD7E71Ge/bzd27+APu1Sr+ATqP3j0zgxPtAAAAAElFTkSuQmCC"
+         height="1"
+         width="1" /></mask><mask
+       id="mask3384"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3386"><g
+           id="g3388"
+           clip-path="url(#clipPath3380)"><g
+             id="g3390"><g
+               id="g3392"
+               transform="matrix(92,0,0,157,888,469)"><image
+                 id="image3394"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAACdCAYAAAA5Wx9JAAAABHNCSVQICAgIfAhkiAAABIZJREFUeJzt111rs0gYxvHL92AipbYHIe1Jv//3CjlopMYXMmqcPdgdH03s7lOWvWDh+sPQUDWUX4c7Ew+AxUqe5639Wv1m1q6ywsMduOd5E/b8tfq9rLUT9vy1K3QvHKzv+w9rfl2t52DHcXxY8+vh/CHf9xGGIaIomlYYhkL/h+bYwzCg7/tpDcMwoQN/gXueN2EnSYI0TbHdbrHdbpEkyYQu8PWstRO2MQZN06BpGrRtCwATurV2CR5FEdI0RZ7neHl5QZ7nyLIMSZIgCALN9JXcnL7dbjDGoKoqFEWB8/kM4NeIcfeF89kdRRF2ux1eX1/x/v6Ow+GAPM+RpimiKJpGi1o2jiP6vkfbtiiKAsfjEZ7noes6GGPQ9z1utxs8z/t+hx8OB3x8fGC/3yPLMsRxrLGykhsnXdehqiqcTicAQNu2+Pr6wuVymdweRoqb4bvdDnmeY7/f4+3tDU9PT9hsNgJfyYFfr1eUZQkAKMsSu91u9fNv9ZTiPjizLMPT0xOen58Xc1z9aj6/AeByuSBN0wX2vMU53O30IAgQRRHiOEaSJEiSBJvNRuArOXAASJIEcRwjiiIEQTDt7LlZeP8GDn2OP18CX+bO4M5nbrdm9QDucv+ZtaWW/cRI5zxyAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInF353wVq7utSynzo9gFtrMY7j9PN2u00LADzP++/++v9h1tqF0dxuDT6cPzhH7vseXdfBGANjDAAgCAKB3+XAnVPXdej7foE/h1/s8HEcMQwDjDFo2xZVVaEsSwDAZrOB7/sCv8tt0uv1irIsUVUV2raFMQbDMGAcx8X94fwhh13XNYqiwOl0AgBcLhfEcSzwlZxd13Woqgqn0wlFUaCu6wW62+UL8L7v0bYtiqLA8XgEAJRliTRNEUURfF+HmrXW7IqiQNu26Pt+CW6thed500N1XePz8xPWWjRNgyzLkCTJNL+1w5e5Ge3meFVVKIoC5/MZdV1P4O7e1R0OAMYYlGWJJEkQhqHGyd90P5KbpkHTNKs73ANggT+Pe77vIwxDRFE0LYft7lGPOUyH3vf9tO5n+AIcAHzff1jz62q9Ofr9ml+fwF3zOa2Z/fPm5+61b50P4NMFQf+rvvt6/we8Kp4iURf8WgAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3380"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3382"
+         d="m 888,626 92,0 0,-157 -92,0 0,157 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3376"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3378"
+         d="m 888,626 92,0 0,-157 -92,0 0,157 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3354"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3356"
+         d="m 1116,527 26.006,0 0,3 -26.006,0 0,-3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3350"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3352"
+         d="m 1116,530 26.01,0 0,-3 -26.01,0 0,3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3328"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3330"
+         d="m 1057.994,527 11.006,0 0,3 -11.006,0 0,-3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3324"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3326"
+         d="m 1057.99,530 26,0 0,-3 -26,0 0,3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3302"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3304"
+         d="m 1000,527 26.006,0 0,3 -26.006,0 0,-3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3298"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3300"
+         d="m 1000,530 26.01,0 0,-3 -26.01,0 0,3 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3272"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3274"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3260"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3262"><g
+           id="g3264"
+           clip-path="url(#clipPath3256)"><g
+             id="g3266"><g
+               id="g3268"
+               transform="matrix(62,0,0,84,1107,495)"><image
+                 id="image3270"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3256"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3258"
+         d="m 1107,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3252"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3254"
+         d="m 1107,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3226"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3228"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3214"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3216"><g
+           id="g3218"
+           clip-path="url(#clipPath3210)"><g
+             id="g3220"><g
+               id="g3222"
+               transform="matrix(62,0,0,84,1049,495)"><image
+                 id="image3224"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3210"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3212"
+         d="m 1049,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3206"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3208"
+         d="m 1049,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3180"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3182"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3168"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3170"><g
+           id="g3172"
+           clip-path="url(#clipPath3164)"><g
+             id="g3174"><g
+               id="g3176"
+               transform="matrix(62,0,0,84,991,495)"><image
+                 id="image3178"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3164"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3166"
+         d="m 991,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3160"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3162"
+         d="m 991,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3152"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3154"
+         d="m 897,482 239.999,0 0,135 -239.999,0 0,-135 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3126"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3128"
+         d="m 887,628 270,0 0,-182 -270,0 0,182 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3118"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3120"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3634-8"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3636-7"
+         d="m 570.26,532 c 0,-30.785 24.955,-55.742 55.74,-55.742 l 0,0 c 30.784,0 55.74,24.957 55.74,55.742 l 0,0 c 0,30.784 -24.956,55.74 -55.74,55.74 l 0,0 c -30.785,0 -55.74,-24.956 -55.74,-55.74" /></clipPath><clipPath
+       id="clipPath3642-3"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3644-4"
+         d="m 558.314,543.945 139.351,0 0,-78.633 -139.351,0 0,78.633 z" /></clipPath><mask
+       id="mask3650-5"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3652-7"><g
+           id="g3654-7"
+           clip-path="url(#clipPath3646-3)"><g
+             id="g3656-5"><g
+               id="g3658-1"
+               transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"><image
+                 id="image3660-3"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAABCJJREFUeJzt3UFvskwYheEDAmNQYkq7MLab/v//1bhQUgqMwjDMt3gzBJTmy7Ol50omNSLdcAcfcEEAwGFBEARLb9Mf4dxiFgjwEEwQBGMs09f0Nzjnxlimr73Iv/BhhGH4tKbbaZ18GMMwPK3p9mi6UxiGiKIIcRyPK4oiRrNy01istTDGwBiDrutgrZ1FEwH/QvCxKKWQpil2ux12ux2UUmM0DGadnHNjLG3bQmuNpmmgtcb9fkff97DWAsA8mDiOkaYp8jzH6+sr8jxHlmVQSmGz2XCmWSE/pwzDgLZt0TQNvr+/cb1eURTFbDsARNPZJY5j7Pd7vL294ePjA6fTCXmeI01TxHE8fjXRujjn0Pc9brcbyrLE+XxGHMew1qLrOhhjYK2Ftfb3M8zpdMLn5yeOxyOyLEOSJPxaWqlhGGCMgdYal8sFSikYY1DXNaqqwu12gzEGQRAszzD7/R55nuN4POL9/R2HwwHb7ZbBrNQwDOi6Dk3TIEkS3O93XC4XpGmKJEnGcQT45SrJD75ZluFwOODl5WU2x9B6+Pmk6zpEUQStNdI0fbrYeQrGvxmGITabDeI4RpIkUEpBKYXtdstgVsgHE4Yh2rad3UbxA+/0Bl70+A98NNN4povBrItzbnbMnXOw1qLv+/FyehiG34Px/BlnadF6DcMwhuL/Tn8q4HUyAZjfj/E38fzr6VcSg6HR48zyOL8ADIYWLIXiMRgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBI5NfHEP/fwyJpHaTH+SkY/yha/9daOy4AfG71yvgHm/s1PfZL4UTTHaeRGGPQdR3atkXbtgCAzWbDYFbGB+OPc9d1MMbM4pmGMzvD+Keit20LrTWqqkJZlgCA7XaLMAwZzMr4k8T9fkdZlqiqClprtG2Lvu8xDMPs89F0Jx9LXdcoigLn8xkA8PPzgyRJGMwK+WPfdR2qqsL5fEZRFKjrehaNP8vMgjHGQGuNoijw9fUFACjLEmmaIo5jhCEvqtZo6dgXRQGtNYwx82CccwiCYNyprmtcLhc459A0DbIsg1JqnF94hlkXP6P4OaaqKhRFgev1irqux2D8ZxfPMADQti3KsoRSClEU8etoxR5HkqZp0DTN4hkmAOCAf5fLYRgiiiLEcTwuH4v/DK2Pj8FHY4wZ1+MMMwsGAMIwfFrT7bRO02ge13T7GIw3nVM4s/w90/suS3d9n4IZNzCUP+23nwf+AzNnFIrywW/wAAAAAElFTkSuQmCC"
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3646-3"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3648-7"
+         d="m 558.314,543.945 139.351,0 0,-78.634 -139.351,0 0,78.634 z" /></clipPath><mask
+       id="mask3662-9"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3664-6"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAAAAAAc13L4AAAAAXNCSVQI5gpbmQAAAdJJREFUaIHt2rFu2zAUheFDirICJUZQt0OQdun7v1fgwRHqylJMkbyng1S0He5aarj/C/gDLWnhcQAAONSNfxTOwdXkkCBXjIP33vtqp0OIiAiIAMCHtm1DLQ0hJaWlCBjgfOj6x8cu+EoYKXGe5nsuCHC+7U+fT8euqfLckBKnH+8DKQgOvn368u311Le+ggVg/rie27KkUraTef3+cjzU+Z8kzZcu3caP5NZn5un08vX5oRJmmQ73S39o3PY2df3x+VPXVHlmZAlz3wXvHALgnG/aQ9c9VML4GDxIrt8ZOO980zR1MM47lpyLbBjArVXAAIDkkgvBOq/zP5EiRYTEDjDgGnaBAUgCe8FsGUbLMFqG0TKMlmG0DKNlGC3DaBlGyzBahtEyjJZhtAyjZRgtw2gZRsswWobRMoyWYbQMo2UYLcNoGUZru0r+fWX5//v7lwMAUCillCprHpZShMINQ0pJS4yoc+NfYlxSEXI9GclxHq+osxKh3K/jHLMACKDkeBvO+FlnP0NZxvNwi1mIAEqahzdcay2LJM3D2zAnIQKdpNuFU73NVYnj8H5LAq4ng3ituEbLcZrmJIQDXPWdXk4p5Q2zmwXj3radwF5Wr78ATrQFVxEFtwQAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><clipPath
+       id="clipPath3634-8-0"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3636-7-9"
+         d="m 570.26,532 c 0,-30.785 24.955,-55.742 55.74,-55.742 l 0,0 c 30.784,0 55.74,24.957 55.74,55.742 l 0,0 c 0,30.784 -24.956,55.74 -55.74,55.74 l 0,0 c -30.785,0 -55.74,-24.956 -55.74,-55.74" /></clipPath><clipPath
+       id="clipPath3642-3-4"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3644-4-2"
+         d="m 558.314,543.945 139.351,0 0,-78.633 -139.351,0 0,78.633 z" /></clipPath><mask
+       id="mask3650-5-0"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3652-7-6"><g
+           id="g3654-7-6"
+           clip-path="url(#clipPath3646-3-3)"><g
+             id="g3656-5-4"><g
+               id="g3658-1-6"
+               transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"><image
+                 id="image3660-3-1"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAABCJJREFUeJzt3UFvskwYheEDAmNQYkq7MLab/v//1bhQUgqMwjDMt3gzBJTmy7Ol50omNSLdcAcfcEEAwGFBEARLb9Mf4dxiFgjwEEwQBGMs09f0Nzjnxlimr73Iv/BhhGH4tKbbaZ18GMMwPK3p9mi6UxiGiKIIcRyPK4oiRrNy01istTDGwBiDrutgrZ1FEwH/QvCxKKWQpil2ux12ux2UUmM0DGadnHNjLG3bQmuNpmmgtcb9fkff97DWAsA8mDiOkaYp8jzH6+sr8jxHlmVQSmGz2XCmWSE/pwzDgLZt0TQNvr+/cb1eURTFbDsARNPZJY5j7Pd7vL294ePjA6fTCXmeI01TxHE8fjXRujjn0Pc9brcbyrLE+XxGHMew1qLrOhhjYK2Ftfb3M8zpdMLn5yeOxyOyLEOSJPxaWqlhGGCMgdYal8sFSikYY1DXNaqqwu12gzEGQRAszzD7/R55nuN4POL9/R2HwwHb7ZbBrNQwDOi6Dk3TIEkS3O93XC4XpGmKJEnGcQT45SrJD75ZluFwOODl5WU2x9B6+Pmk6zpEUQStNdI0fbrYeQrGvxmGITabDeI4RpIkUEpBKYXtdstgVsgHE4Yh2rad3UbxA+/0Bl70+A98NNN4povBrItzbnbMnXOw1qLv+/FyehiG34Px/BlnadF6DcMwhuL/Tn8q4HUyAZjfj/E38fzr6VcSg6HR48zyOL8ADIYWLIXiMRgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBI5NfHEP/fwyJpHaTH+SkY/yha/9daOy4AfG71yvgHm/s1PfZL4UTTHaeRGGPQdR3atkXbtgCAzWbDYFbGB+OPc9d1MMbM4pmGMzvD+Keit20LrTWqqkJZlgCA7XaLMAwZzMr4k8T9fkdZlqiqClprtG2Lvu8xDMPs89F0Jx9LXdcoigLn8xkA8PPzgyRJGMwK+WPfdR2qqsL5fEZRFKjrehaNP8vMgjHGQGuNoijw9fUFACjLEmmaIo5jhCEvqtZo6dgXRQGtNYwx82CccwiCYNyprmtcLhc459A0DbIsg1JqnF94hlkXP6P4OaaqKhRFgev1irqux2D8ZxfPMADQti3KsoRSClEU8etoxR5HkqZp0DTN4hkmAOCAf5fLYRgiiiLEcTwuH4v/DK2Pj8FHY4wZ1+MMMwsGAMIwfFrT7bRO02ge13T7GIw3nVM4s/w90/suS3d9n4IZNzCUP+23nwf+AzNnFIrywW/wAAAAAElFTkSuQmCC"
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3646-3-3"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3648-7-6"
+         d="m 558.314,543.945 139.351,0 0,-78.634 -139.351,0 0,78.634 z" /></clipPath><mask
+       id="mask3662-9-4"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3664-6-5"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAAAAAAc13L4AAAAAXNCSVQI5gpbmQAAAdJJREFUaIHt2rFu2zAUheFDirICJUZQt0OQdun7v1fgwRHqylJMkbyng1S0He5aarj/C/gDLWnhcQAAONSNfxTOwdXkkCBXjIP33vtqp0OIiAiIAMCHtm1DLQ0hJaWlCBjgfOj6x8cu+EoYKXGe5nsuCHC+7U+fT8euqfLckBKnH+8DKQgOvn368u311Le+ggVg/rie27KkUraTef3+cjzU+Z8kzZcu3caP5NZn5un08vX5oRJmmQ73S39o3PY2df3x+VPXVHlmZAlz3wXvHALgnG/aQ9c9VML4GDxIrt8ZOO980zR1MM47lpyLbBjArVXAAIDkkgvBOq/zP5EiRYTEDjDgGnaBAUgCe8FsGUbLMFqG0TKMlmG0DKNlGC3DaBlGyzBahtEyjJZhtAyjZRgtw2gZRsswWobRMoyWYbQMo2UYLcNoGUZru0r+fWX5//v7lwMAUCillCprHpZShMINQ0pJS4yoc+NfYlxSEXI9GclxHq+osxKh3K/jHLMACKDkeBvO+FlnP0NZxvNwi1mIAEqahzdcay2LJM3D2zAnIQKdpNuFU73NVYnj8H5LAq4ng3ituEbLcZrmJIQDXPWdXk4p5Q2zmwXj3radwF5Wr78ATrQFVxEFtwQAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><clipPath
+       id="clipPath3592-5"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3594-9"
+         d="m 730.778,549 12,0 0,-12 -12,0 0,12 z" /></clipPath><clipPath
+       id="clipPath3566-8"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3568-8"
+         d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath
+       id="clipPath3570-6"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3572-0"
+         d="m 679,535.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath
+       id="clipPath3520-6"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3522-3"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask
+       id="mask3528-3"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3530-7"><g
+           id="g3532-3"
+           clip-path="url(#clipPath3524-5)"><g
+             id="g3534-0"><g
+               id="g3536-4"
+               transform="matrix(93,0,0,68,667,493)"><image
+                 id="image3538-4"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3524-5"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3526-4"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask
+       id="mask3540-4"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3542-1"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg=="
+         height="1"
+         width="1" /></mask><clipPath
+       id="clipPath3592-5-6"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3594-9-5"
+         d="m 730.778,549 12,0 0,-12 -12,0 0,12 z" /></clipPath><clipPath
+       id="clipPath3566-8-1"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3568-8-2"
+         d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath
+       id="clipPath3570-6-5"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3572-0-0"
+         d="m 679,535.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath
+       id="clipPath3520-6-0"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3522-3-3"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask
+       id="mask3528-3-8"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3530-7-0"><g
+           id="g3532-3-9"
+           clip-path="url(#clipPath3524-5-5)"><g
+             id="g3534-0-9"><g
+               id="g3536-4-3"
+               transform="matrix(93,0,0,68,667,493)"><image
+                 id="image3538-4-0"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3524-5-5"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3526-4-5"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask
+       id="mask3540-4-8"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3542-1-9"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg=="
+         height="1"
+         width="1" /></mask><clipPath
+       id="clipPath3942-2"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3944-1"
+         d="m 1337.7,554.569 67.31,0 0,-64.569 -67.31,0 0,64.569 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3912-3"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3914-9"
+         d="m 1404.777,549.002 12,0 0,11.998 -12,0 0,-11.998 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3908-4"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3910-0"
+         d="m 1404.78,561 12,0 0,-12 -12,0 0,12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3886-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3888-7"
+         d="m 1363,547.865 32,0 0,12 -32,0 0,-12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3882-9"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3884-9"
+         d="m 1363,559.865 32,0 0,-12.002 -32,0 0,12.002 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3852-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3854-6"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAAAAACTooUSAAAAAXNCSVQI5gpbmQAAAXhJREFUWIXt2T9v3DAMBfBHWj4Fzh2CXjsEaZd+/+8VZGiN+v4Y1cni6+ADmqUjnQ7kqEE/ULQXPgEAQLBB8S8lAnE3SZCrKFBVVd8+CTMzA5EAaOr7PrmShC211sWABNGUh8fHnNRTtKVcrzMWY4JoPxw/Hw+585sl2cp5/AkzMgm033/59nIcevUCAavz+Cq3Upvce3z5/nzY+T0r7XZ+w/zrpMJ1jvvj89enB0/x94Rpn5PK/VvNw+HpU+78xFZwGnJSAAkQ0a7f5fzgKSLv+k5FgAQAoqJd1zmK6DqVdWppPZK1vES8u93xj/hHhRhiiCGGGGKIIYYYYoghhhhiiCGGGOL/Jt73ciRJuinvr08AQKO11vzCALbWjMa7SFqrt1LgutEtt9qMXHu0pcznCc5b6/NcFgOQQFvKZXzDyXszP17KYkQCrc7jKyb/9GGcqxGJYvXyg9ctEpZLNXDtEWXaJEWqRgggWyZl/IA08EMST2DTVPcPY4fdi0eNNAgAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3840-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3842-8"><g
+           id="g3844-1"
+           clip-path="url(#clipPath3836-1)"><g
+             id="g3846-7"><g
+               id="g3848-5"
+               transform="matrix(113,0,0,68,1351,505)"><image
+                 id="image3850-5"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAYAAAC2ydrOAAAABHNCSVQICAgIfAhkiAAAA1NJREFUeJztnc1uozAURj8HjCMCikq7iNJu+v7vVXXRovJn1RDiWUztMQnttIuQmat7pKugAFn4yDZk8V0BwGIGIcTc18wVsXZWFQROJAohvMDwmLke1lovMDx2xO7AyVqtVmcVnmeWw8k6Ho9nFZ6Pw5tWqxXiOIaU0lccxyzyCoQCD4cDhmHwdTgcvEjgQ6IQwgtUSiFNU2w2G2w2GyilvEiWuBzWWi/QGIOu69B1HbTWAOBFWmunEqWUSNMURVHg9vYWRVEgz3MopRBFEe+RC+H2vXEcYYxB0zQoyxKvr68A/iyv7ro43AullMiyDHd3d3h4eMB+v0dRFEjTFFJKv6wyl+d4PGIYBmitUZYlnp6eIIRA3/cwxmAYBozjCCHE5zNxv9/j8fERu90OeZ4jSRJeUhfCLaV936NpGjw/PwMAtNZ4e3tDXdfexdly6vbELMtQFAV2ux3u7++x3W6xXq9Z4kI4ie/v76iqCgBQVRWyLJt9Rpl9OnUPN3meY7vd4ubmZrIvMpcl3A8BoK5rpGk6ERgyeU90MzKKIkgpkSQJlFJQSmG9XrPEhXASAUAphSRJIKVEFEV+BoYe4tMfcCJDoWGxxMvj3hHdmIc+5sb/TKLD2Z4r5vL8ZNz5nYEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEAn2a7uWji02Iuz0/H/kyiC0x1n+M4+gI4kX8JXFSmq9DHnMw4vDEUNwyDz5t24akclbkMYWitMQZ93/vM7zDA3TGZiWGEv9YaTdP4+GKOj16O0/jopmmgtYYx5qwnBvAh8bQHQ9u2KMvSB4jXdc1B7gsyF+ReliXatp2InHSocTedRvgDvwPEuaXC8sz5KMsSWmsMwzCVaK2FEMLf1LYtXl5eYK1F13Xc3OQKfNXcpG1bL9FdOzsTAcAYg6qquM3QlfiqzdDpTPSt98LeGNzw6/p8p+HXrESAW+/9S3y39R43wfwP+FsTzDOJ/gTL++f47K+3XyWNnXDxB1SBAAAAAElFTkSuQmCC"
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3836-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3838-6"
+         d="m 1351,573 113,0 0,-68 -113,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3832-3"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3834-3"
+         d="m 1351,573 113,0 0,-68 -113,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3824-4"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3826-5"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3798-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3800-3"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAAAAACTooUSAAAAAXNCSVQI5gpbmQAAAZ9JREFUWIXt2U9v1DAQBfA348lmyXa1FdBSgRDf/4tVe4CI7J+oXtvzOKQIOCOnF8/Ft/lpZCeHeQIAgGCF4h9KBFLdJEEuokBVVevOSbi7OwiDiIZN14WqJOE5pZQdMEBtO+yGPmhN0XO8Xmdkp4mEfv/+w/2u13p3SZZ4Hn/AnTRo2B6evjwd3lnFGT3N47PcYipiIrY9PH77+nHotBpIv52PmH+eVGiQsBnuHz5/2m1qii8TprveVJa3av2wP9xt6j0dlojT0JsCMJAk1LptVRH9pgsqAhjoJedC0YqfBxGCytLfCJZcsgM1/3Qi8ru7gnQv7mQ17t9SgEutBEIBYEXvVVy1mtjEJjaxiU1sYhOb2MQmNrGJTWxiE5v4P2XLUXlt9Xd7AwA6vZRSLwxgKcXpfBVJL+kWI0LNjW68peLkMqPnOJ8nbCvuV/1lOs8xO5aNbo6X8YhTzR2y387H8RKzEwZ6msdnTDWzgCV9GOfkhFE8Xb7zuu9D9YTlkhxcZkScelshRUpOCCBqXdfZOkkZ3yANfJPEE1g11f0FocoCRBRb0tkAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3786-0"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3788-7"><g
+           id="g3790-3"
+           clip-path="url(#clipPath3782-0)"><g
+             id="g3792-9"><g
+               id="g3794-3"
+               transform="matrix(113,0,0,68,1351,444)"><image
+                 id="image3796-9"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAYAAAC2ydrOAAAABHNCSVQICAgIfAhkiAAAA59JREFUeJztnclurDoURTdgmkAhSmlLiaL8/49FGSQodFZM5zd4sstUkdsMQnKPzpKsQgVMWDo2ZrCPB0BjBc/z1v5mvhGtV1XBw4lEz/OsQPeY+T601lage2wQ5sDI8n3/bLjnme0wsuZ5PhvueQEcK873fQRBgCiKEIYhwjBEEAQs8htwBY7jiGEY7BjH0YoEnEr0fR9CCCRJgjRNkWUZ0jRFHMdWJEvcDq21FaiUQtd16LoOUkoAsCK11hCmCoMgQBzHyPMcl5eXuLq6wn6/R5ZliOPYSmSRX49Z96ZpglIKTdOgLEu8vb0BOE6v5joBwE6jSZKgKAocDgc8PDzgcDigKApcXFxACMECN2SeZwzDACklyrLE8/MzPM9D3/dQSmEYBkzTBM/zjpVoptKiKHB7e4unpyc8Pj7i+voaaZoiDEO7NjJfi5lK+75H0zR4eXkBAEgp8f7+jrqu7cxoK9FMp1EUIU1T7Pd73Nzc4P7+Hnd3d8iyDFEUscSNMBI/Pj5QVRUAoKoq7HY7xHEMIcTiHeXs7VQIgTiOkaYp8jxHURTY7XZWIk+pX4+7HgJAXdf2JdMIdBHmJncAx7fVMAyRJAlL3BAjEQDiOLZbPneX4HqwEud5xjRNGMcR4zhimiZorRf7R5a4DaaQgiBYPPfPnr9wP+cYiebX3VAC/BluS8yzdsdn+MBxOjX7j2mazvYizM/FrpCn6+LpGsn8XM72DCzv34M3fgRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQQQn53gdKnv42+f/ZlEk/HmJi+aAXAi/xaYsEQzXB9rMoV7oytuGAabN23CU4MgYIkb4IbWKqXQ973N/F4LTVxUohvhL6VE0zQ2vjhJEs473YjT+OimaSClhFJqNcJ0EVprBLZti7IsbYB4XdecPLwha0HuZVmibduFyEWHGnPTaYQ/8H+AOKfxb8+aj7IsIaXEMAxLiSYi2tzUti1eX1+htUbXdcjz3Hap4eThbfhVc5O2ba1Ec+1qJQKAUgpVVa1G+DNfz6/aDJ1Wom2957ZUMM2+wjBcRPizxO34k4ZfqxIBbr33k/jT1nvcBPMf4HdNMM8k2hMs78fx2ae3/wBR6gt9OOvm0AAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3782-0"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3784-8"
+         d="m 1351,512 113,0 0,-68 -113,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3778-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3780-0"
+         d="m 1351,512 113,0 0,-68 -113,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3770-5"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3772-0"
+         d="m 1341,490 129,0 0,89 -129,0 0,-89 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3748-6"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3750-3"
+         d="m 1214,628 270,0 0,-182 -270,0 0,182 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3726-6"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3728-1"
+         d="m 652.002,520.002 12,0 0,11.998 -12,0 0,-11.998 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3722-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3724-4"
+         d="m 652,532 12.002,0 0,-12 -12.002,0 0,12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3700-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3702-8"
+         d="m 592,518.865 32,0 0,12 -32,0 0,-12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3696-9"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3698-6"
+         d="m 592,530.865 32,0 0,-12.002 -32,0 0,12.002 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3688-4"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3690-8"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3662-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3664-9"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAAAAAAc13L4AAAAAXNCSVQI5gpbmQAAAdJJREFUaIHt2rFu2zAUheFDirICJUZQt0OQdun7v1fgwRHqylJMkbyng1S0He5aarj/C/gDLWnhcQAAONSNfxTOwdXkkCBXjIP33vtqp0OIiAiIAMCHtm1DLQ0hJaWlCBjgfOj6x8cu+EoYKXGe5nsuCHC+7U+fT8euqfLckBKnH+8DKQgOvn368u311Le+ggVg/rie27KkUraTef3+cjzU+Z8kzZcu3caP5NZn5un08vX5oRJmmQ73S39o3PY2df3x+VPXVHlmZAlz3wXvHALgnG/aQ9c9VML4GDxIrt8ZOO980zR1MM47lpyLbBjArVXAAIDkkgvBOq/zP5EiRYTEDjDgGnaBAUgCe8FsGUbLMFqG0TKMlmG0DKNlGC3DaBlGyzBahtEyjJZhtAyjZRgtw2gZRsswWobRMoyWYbQMo2UYLcNoGUZru0r+fWX5//v7lwMAUCillCprHpZShMINQ0pJS4yoc+NfYlxSEXI9GclxHq+osxKh3K/jHLMACKDkeBvO+FlnP0NZxvNwi1mIAEqahzdcay2LJM3D2zAnIQKdpNuFU73NVYnj8H5LAq4ng3ituEbLcZrmJIQDXPWdXk4p5Q2zmwXj3radwF5Wr78ATrQFVxEFtwQAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3650-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3652-6"><g
+           id="g3654-8"
+           clip-path="url(#clipPath3646-6)"><g
+             id="g3656-3"><g
+               id="g3658-9"
+               transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"><image
+                 id="image3660-2"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAABCJJREFUeJzt3UFvskwYheEDAmNQYkq7MLab/v//1bhQUgqMwjDMt3gzBJTmy7Ol50omNSLdcAcfcEEAwGFBEARLb9Mf4dxiFgjwEEwQBGMs09f0Nzjnxlimr73Iv/BhhGH4tKbbaZ18GMMwPK3p9mi6UxiGiKIIcRyPK4oiRrNy01istTDGwBiDrutgrZ1FEwH/QvCxKKWQpil2ux12ux2UUmM0DGadnHNjLG3bQmuNpmmgtcb9fkff97DWAsA8mDiOkaYp8jzH6+sr8jxHlmVQSmGz2XCmWSE/pwzDgLZt0TQNvr+/cb1eURTFbDsARNPZJY5j7Pd7vL294ePjA6fTCXmeI01TxHE8fjXRujjn0Pc9brcbyrLE+XxGHMew1qLrOhhjYK2Ftfb3M8zpdMLn5yeOxyOyLEOSJPxaWqlhGGCMgdYal8sFSikYY1DXNaqqwu12gzEGQRAszzD7/R55nuN4POL9/R2HwwHb7ZbBrNQwDOi6Dk3TIEkS3O93XC4XpGmKJEnGcQT45SrJD75ZluFwOODl5WU2x9B6+Pmk6zpEUQStNdI0fbrYeQrGvxmGITabDeI4RpIkUEpBKYXtdstgVsgHE4Yh2rad3UbxA+/0Bl70+A98NNN4povBrItzbnbMnXOw1qLv+/FyehiG34Px/BlnadF6DcMwhuL/Tn8q4HUyAZjfj/E38fzr6VcSg6HR48zyOL8ADIYWLIXiMRgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBI5NfHEP/fwyJpHaTH+SkY/yha/9daOy4AfG71yvgHm/s1PfZL4UTTHaeRGGPQdR3atkXbtgCAzWbDYFbGB+OPc9d1MMbM4pmGMzvD+Keit20LrTWqqkJZlgCA7XaLMAwZzMr4k8T9fkdZlqiqClprtG2Lvu8xDMPs89F0Jx9LXdcoigLn8xkA8PPzgyRJGMwK+WPfdR2qqsL5fEZRFKjrehaNP8vMgjHGQGuNoijw9fUFACjLEmmaIo5jhCEvqtZo6dgXRQGtNYwx82CccwiCYNyprmtcLhc459A0DbIsg1JqnF94hlkXP6P4OaaqKhRFgev1irqux2D8ZxfPMADQti3KsoRSClEU8etoxR5HkqZp0DTN4hkmAOCAf5fLYRgiiiLEcTwuH4v/DK2Pj8FHY4wZ1+MMMwsGAMIwfFrT7bRO02ge13T7GIw3nVM4s/w90/suS3d9n4IZNzCUP+23nwf+AzNnFIrywW/wAAAAAElFTkSuQmCC"
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3646-6"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3648-8"
+         d="m 558.314,543.945 139.351,0 0,-78.634 -139.351,0 0,78.634 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3642-7"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3644-3"
+         d="m 558.314,543.945 139.351,0 0,-78.633 -139.351,0 0,78.633 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3634-3"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3636-8"
+         d="m 570.26,532 c 0,-30.785 24.955,-55.742 55.74,-55.742 l 0,0 c 30.784,0 55.74,24.957 55.74,55.742 l 0,0 c 0,30.784 -24.956,55.74 -55.74,55.74 l 0,0 c -30.785,0 -55.74,-24.956 -55.74,-55.74"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3610-5"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3612-4"
+         d="m 652.333,574.333 101,0 0,-79.333 -101,0 0,79.333 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3592-6"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3594-98"
+         d="m 730.778,549 12,0 0,-12 -12,0 0,12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3570-0"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3572-8"
+         d="m 679,535.865 32,0 0,12 -32,0 0,-12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3566-5"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3568-3"
+         d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3540-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3542-0"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg=="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3528-8"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3530-9"><g
+           id="g3532-7"
+           clip-path="url(#clipPath3524-3)"><g
+             id="g3534-3"><g
+               id="g3536-8"
+               transform="matrix(93,0,0,68,667,493)"><image
+                 id="image3538-8"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3524-3"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3526-7"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3520-9"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3522-1"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3498-7"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3500-1"
+         d="m 560,628 270,0 0,-182 -270,0 0,182 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3490-4"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3492-5"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3476-8"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3478-3"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABHcAAAK/CAAAAADGr34kAAAAAXNCSVQI5gpbmQAACLFJREFUeJzt1DEBACAMwDDAv+fhohwkCnp1zwJIndcBwHd8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4DaBSkuBn0AocgUAAAAAElFTkSuQmCC"
+         height="1"
+         width="1" /></mask><clipPath
+       id="clipPath3470-9"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3472-6"
+         d="m 538,215 954,0 0,118 -954,0 0,-118 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3460-8"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3462-0"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABHcAAAK/CAAAAADGr34kAAAAAXNCSVQI5gpbmQAACLFJREFUeJzt1DEBACAMwDDAv+fhohwkCnp1zwJIndcBwHd8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4DaBSkuBn0AocgUAAAAAElFTkSuQmCC"
+         height="1"
+         width="1" /></mask><clipPath
+       id="clipPath3454-4"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3456-3"
+         d="m 554,720 958,0 0,204 -958,0 0,-204 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3432-5"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3434-1"
+         d="m 904,587 32,0 0,12 -32,0 0,-12 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3428-5"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3430-0"
+         d="m 904,599 32,0 0,-12.002 -32,0 0,12.002 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3420-8"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3422-5"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3396-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3398-2"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAACdCAAAAAAcMECVAAAAAXNCSVQI5gpbmQAAAZdJREFUaIHt27tu20AQheEzy6Vo0BKMKCkMJ03e/70MFzYR3YisljsnBQXETZpg1J0pt/gwGGz7GwAAhtjhX9UMFsmTIFfckFJKKWx7wt3dQWQAKfd9n6N0wpda6+JAhqU8jI+PQ05BuC/lcpmxODMs9eP+6343dCF3J1s5TR9wJ7Mh9dtvP172Y58CbMDrPL3atdRmt81ffj7vNiF3oV9Pb5h/HZNxvfl2//z96SEI/33AYTvkZLffMoy7py9DF4K3guM45AQgA2ap6zfD8BCEY9j0XTIDMgBYstR1XQyOrku2XjivT7ZOAI5PUMz3+8cIFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwv97bkEBSZIR4GcpAwCd3loLaX7YWnM6bzjprV5LQVQhUq61Oblu7kuZTwfEtS2nuSwOIIO+lPP0hmNglTOdy+JEBr3O0ysOoT3RNFcnMs3r+Z2X4BLqXB1cN0c5RDdc1QkD7E71Ge/bzd27+APu1Sr+ATqP3j0zgxPtAAAAAElFTkSuQmCC"
+         height="1"
+         width="1" /></mask><mask
+       id="mask3384-8"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3386-8"><g
+           id="g3388-5"
+           clip-path="url(#clipPath3380-6)"><g
+             id="g3390-8"><g
+               id="g3392-8"
+               transform="matrix(92,0,0,157,888,469)"><image
+                 id="image3394-9"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAACdCAYAAAA5Wx9JAAAABHNCSVQICAgIfAhkiAAABIZJREFUeJzt111rs0gYxvHL92AipbYHIe1Jv//3CjlopMYXMmqcPdgdH03s7lOWvWDh+sPQUDWUX4c7Ew+AxUqe5639Wv1m1q6ywsMduOd5E/b8tfq9rLUT9vy1K3QvHKzv+w9rfl2t52DHcXxY8+vh/CHf9xGGIaIomlYYhkL/h+bYwzCg7/tpDcMwoQN/gXueN2EnSYI0TbHdbrHdbpEkyYQu8PWstRO2MQZN06BpGrRtCwATurV2CR5FEdI0RZ7neHl5QZ7nyLIMSZIgCALN9JXcnL7dbjDGoKoqFEWB8/kM4NeIcfeF89kdRRF2ux1eX1/x/v6Ow+GAPM+RpimiKJpGi1o2jiP6vkfbtiiKAsfjEZ7noes6GGPQ9z1utxs8z/t+hx8OB3x8fGC/3yPLMsRxrLGykhsnXdehqiqcTicAQNu2+Pr6wuVymdweRoqb4bvdDnmeY7/f4+3tDU9PT9hsNgJfyYFfr1eUZQkAKMsSu91u9fNv9ZTiPjizLMPT0xOen58Xc1z9aj6/AeByuSBN0wX2vMU53O30IAgQRRHiOEaSJEiSBJvNRuArOXAASJIEcRwjiiIEQTDt7LlZeP8GDn2OP18CX+bO4M5nbrdm9QDucv+ZtaWW/cRI5zxyAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInF353wVq7utSynzo9gFtrMY7j9PN2u00LADzP++/++v9h1tqF0dxuDT6cPzhH7vseXdfBGANjDAAgCAKB3+XAnVPXdej7foE/h1/s8HEcMQwDjDFo2xZVVaEsSwDAZrOB7/sCv8tt0uv1irIsUVUV2raFMQbDMGAcx8X94fwhh13XNYqiwOl0AgBcLhfEcSzwlZxd13Woqgqn0wlFUaCu6wW62+UL8L7v0bYtiqLA8XgEAJRliTRNEUURfF+HmrXW7IqiQNu26Pt+CW6thed500N1XePz8xPWWjRNgyzLkCTJNL+1w5e5Ge3meFVVKIoC5/MZdV1P4O7e1R0OAMYYlGWJJEkQhqHGyd90P5KbpkHTNKs73ANggT+Pe77vIwxDRFE0LYft7lGPOUyH3vf9tO5n+AIcAHzff1jz62q9Ofr9ml+fwF3zOa2Z/fPm5+61b50P4NMFQf+rvvt6/we8Kp4iURf8WgAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3380-6"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3382-6"
+         d="m 888,626 92,0 0,-157 -92,0 0,157 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3376-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3378-8"
+         d="m 888,626 92,0 0,-157 -92,0 0,157 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3354-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3356-9"
+         d="m 1116,527 26.006,0 0,3 -26.006,0 0,-3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3350-2"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3352-7"
+         d="m 1116,530 26.01,0 0,-3 -26.01,0 0,3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3328-2"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3330-1"
+         d="m 1057.994,527 11.006,0 0,3 -11.006,0 0,-3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3324-6"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3326-2"
+         d="m 1057.99,530 26,0 0,-3 -26,0 0,3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3302-2"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3304-7"
+         d="m 1000,527 26.006,0 0,3 -26.006,0 0,-3 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3298-9"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3300-4"
+         d="m 1000,530 26.01,0 0,-3 -26.01,0 0,3 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3272-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3274-5"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3260-5"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3262-2"><g
+           id="g3264-6"
+           clip-path="url(#clipPath3256-0)"><g
+             id="g3266-6"><g
+               id="g3268-0"
+               transform="matrix(62,0,0,84,1107,495)"><image
+                 id="image3270-6"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3256-0"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3258-5"
+         d="m 1107,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3252-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3254-3"
+         d="m 1107,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3226-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3228-8"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3214-5"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3216-2"><g
+           id="g3218-9"
+           clip-path="url(#clipPath3210-9)"><g
+             id="g3220-8"><g
+               id="g3222-2"
+               transform="matrix(62,0,0,84,1049,495)"><image
+                 id="image3224-4"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3210-9"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3212-3"
+         d="m 1049,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3206-7"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3208-1"
+         d="m 1049,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><mask
+       id="mask3180-7"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3182-1"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII="
+         height="1"
+         width="1" /></mask><mask
+       id="mask3168-6"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3170-1"><g
+           id="g3172-4"
+           clip-path="url(#clipPath3164-3)"><g
+             id="g3174-6"><g
+               id="g3176-0"
+               transform="matrix(62,0,0,84,991,495)"><image
+                 id="image3178-0"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg=="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3164-3"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3166-1"
+         d="m 991,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3160-9"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3162-3"
+         d="m 991,579 62,0 0,-84 -62,0 0,84 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3152-4"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3154-4"
+         d="m 897,482 239.999,0 0,135 -239.999,0 0,-135 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3126-1"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3128-0"
+         d="m 887,628 270,0 0,-182 -270,0 0,182 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3118-8"
+       clipPathUnits="userSpaceOnUse"><path
+         id="path3120-5"
+         d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z"
+         inkscape:connector-curvature="0" /></clipPath><clipPath
+       id="clipPath3722-1-6"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3724-4-6"
+         d="m 652,532 12.002,0 0,-12 -12.002,0 0,12 z" /></clipPath><clipPath
+       id="clipPath3726-6-9"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3728-1-7"
+         d="m 652.002,520.002 12,0 0,11.998 -12,0 0,-11.998 z" /></clipPath><clipPath
+       id="clipPath3696-9-7"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3698-6-3"
+         d="m 592,530.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath
+       id="clipPath3700-1-1"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3702-8-2"
+         d="m 592,518.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath
+       id="clipPath3696-9-7-9"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3698-6-3-5"
+         d="m 592,530.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath
+       id="clipPath3700-1-1-8"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3702-8-2-6"
+         d="m 592,518.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath
+       id="clipPath3722-1-6-1"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3724-4-6-5"
+         d="m 652,532 12.002,0 0,-12 -12.002,0 0,12 z" /></clipPath><clipPath
+       id="clipPath3726-6-9-4"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3728-1-7-6"
+         d="m 652.002,520.002 12,0 0,11.998 -12,0 0,-11.998 z" /></clipPath><clipPath
+       id="clipPath3086-4-0"><path
+         inkscape:connector-curvature="0"
+         d="m 1058,722 374,0 0,-374 -374,0 0,374 z"
+         id="path3088-8-7" /></clipPath><clipPath
+       id="clipPath3100-8-2"><path
+         inkscape:connector-curvature="0"
+         d="m 1029,344 432,0 0,-32 -432,0 0,32 z"
+         id="path3102-2-9" /></clipPath><clipPath
+       id="clipPath3116-4-9"><path
+         inkscape:connector-curvature="0"
+         d="m 1029,756 432,0 0,-32 -432,0 0,32 z"
+         id="path3118-5-1" /></clipPath><clipPath
+       id="clipPath3592-5-68"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3594-9-1"
+         d="m 730.778,549 12,0 0,-12 -12,0 0,12 z" /></clipPath><clipPath
+       id="clipPath3566-8-9"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3568-8-22"
+         d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath
+       id="clipPath3570-6-4"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3572-0-00"
+         d="m 679,535.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath
+       id="clipPath3520-6-4"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3522-3-32"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask
+       id="mask3528-3-5"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><g
+         id="g3530-7-3"><g
+           id="g3532-3-5"
+           clip-path="url(#clipPath3524-5-2)"><g
+             id="g3534-0-0"><g
+               id="g3536-4-5"
+               transform="matrix(93,0,0,68,667,493)"><image
+                 id="image3538-4-00"
+                 xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII="
+                 transform="matrix(1,0,0,-1,0,1)"
+                 height="1"
+                 width="1" /></g></g></g></g></mask><clipPath
+       id="clipPath3524-5-2"
+       clipPathUnits="userSpaceOnUse"><path
+         inkscape:connector-curvature="0"
+         id="path3526-4-1"
+         d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask
+       id="mask3540-4-88"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       maskUnits="userSpaceOnUse"><image
+         id="image3542-1-5"
+         xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg=="
+         height="1"
+         width="1" /></mask></defs><g
+     inkscape:groupmode="layer"
+     id="layer8"
+     inkscape:label="Layer5"
+     transform="translate(436.0495,72.4457)"><g
+       style="display:inline"
+       id="g3508-5-64"
+       transform="matrix(5.09,0,0,-5.09,-201.82504,927.02677)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c -2.209,0 -4,1.791 -4,4 l 0,92 c 0,2.209 1.791,4 4,4 l 92,0 c 2.209,0 4,-1.791 4,-4 L 96,4 C 96,1.791 94.209,0 92,0 L 0,0 z"
+         style="fill:#4fbdee;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3510-0-3" /></g><g
+       style="display:inline"
+       id="g3516-7-0"
+       transform="matrix(5.09,0,0,-5.09,-3586.6755,3426.2166)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3518-2-5" /><g
+         id="g3544-9-2"><g
+           style="opacity:0.119995"
+           clip-path="url(#clipPath3520-6-4)"
+           id="g3546-7-5"><g
+             id="g3548-8-3"><g
+               id="g3550-3-8" /><g
+               mask="url(#mask3528-3-5)"
+               id="g3552-8-72"><g
+                 transform="matrix(93,0,0,68,667,493)"
+                 id="g3554-9-8"><image
+                   width="1"
+                   height="1"
+                   transform="matrix(1,0,0,-1,0,1)"
+                   xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAAP1JREFUeJzt3DGKhEAARcFWvP+VeyNBxJGFHX3BVmU2BvL4DBP1Muec48KyLFfH/NKHrGOMMbbzgdjfsXe8ir+dX+K7ruKv1cf8N8dRr+cDnmfpL9rHvVr5+yw9sIwxPv+h5BGWHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9JfNOUUvrHe3H/MMS3/RPvD1+MA7LP0lx2Fv50N3737X7aX155fE/5u7n+wfv04ph+lQnM8AAAAASUVORK5CYII="
+                   mask="url(#mask3540-4-88)"
+                   id="image3556-9-3" /></g></g></g></g></g></g><g
+       style="display:inline"
+       id="g3558-6-1"
+       transform="matrix(5.09,0,0,-5.09,235.91496,860.85677)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c 0,-1.65 -1.35,-3 -3,-3 l -74,0 c -1.649,0 -3,1.35 -3,3 l 0,50 c 0,1.65 1.351,3 3,3 l 74,0 c 1.65,0 3,-1.35 3,-3 L 0,0 z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3560-5-6" /></g><g
+       style="display:inline"
+       id="g3562-4-0"
+       transform="matrix(5.09,0,0,-5.09,-3586.6755,3426.2166)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3564-6-3" /><g
+         id="g3574-7-9"><g
+           style="opacity:0.5"
+           clip-path="url(#clipPath3566-8-9)"
+           id="g3576-7-8"><g
+             id="g3578-2-9"><g
+               clip-path="url(#clipPath3570-6-4)"
+               id="g3580-1-9"><path
+                 inkscape:connector-curvature="0"
+                 d="m 710.994,535.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z"
+                 style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path3582-0-16" /></g></g></g></g></g><path
+       inkscape:connector-curvature="0"
+       d="m 123.93496,748.87677 -254.5,0 0,-25.45 254.5,0 0,25.45 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3584-1-9"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><path
+       inkscape:connector-curvature="0"
+       d="m 6.8649591,799.77677 -137.4299991,0 0,-25.45 137.4299991,0 0,25.45 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3586-5-0"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><g
+       style="display:inline"
+       id="g3588-5-0"
+       transform="matrix(5.09,0,0,-5.09,-3586.6755,3426.2166)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3590-3-9" /><g
+         id="g3596-7-2"><g
+           style="opacity:0"
+           clip-path="url(#clipPath3592-5-68)"
+           id="g3598-6-5"><path
+             inkscape:connector-curvature="0"
+             d="m 730.777,537 12,0 0,12 -12,0 0,-12 z"
+             style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+             id="path3600-8-1" /></g></g></g><g
+       style="display:inline"
+       id="g3602-7-0"
+       transform="matrix(5.09,0,0,-5.09,188.97176,661.07427)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c 0,0.414 -0.336,0.75 -0.75,0.75 l -2.75,0 -2.5,4 -1,0 1.25,-4 -2.75,0 -0.75,1 -0.75,0 0.5,-1.75 -0.5,-1.75 0.75,0 0.75,1 2.75,0 -1.25,-4 1,0 2.5,4 2.75,0 C -0.336,-0.75 0,-0.414 0,0"
+         style="fill:#00c853;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3604-3-8" /></g><g
+       transform="matrix(1.25,0,0,-1.25,-1884.887,1349.9021)"
+       id="g3012-8"
+       style="display:inline"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         transform="translate(1677.8121,922.30928)"
+         id="g3072-5"
+         style="fill:#333333;fill-opacity:1"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 -285.486,0 -14,-190.491 313.486,0 L 0,0 z"
+           id="path3074-5"
+           style="fill:#101010;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="translate(1691.8121,352.84148)"
+         id="g3076-9"
+         style="fill:#333333;fill-opacity:1"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 -313.486,0 14,-190.491 286.486,0 L 0,0 z"
+           id="path3078-3"
+           style="fill:#101010;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><path
+         inkscape:connector-curvature="0"
+         d="m 1721.07,355.32978 -374,0 0,374 374,0 0,-374 z m 3.332,409 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 0,-380 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 l 378.666,0 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 0,380 0,5.333 c 0,14.729 -11.939,26.667 -26.668,26.667"
+         id="path3080-4"
+         style="fill:#101010;fill-opacity:1;fill-rule:nonzero;stroke:none" /><g
+         transform="translate(290.06807,8.3297801)"
+         id="g3082-3"><g
+           id="g3084-9" /><g
+           id="g3090-2"><g
+             clip-path="url(#clipPath3086-4-0)"
+             id="g3092-8"
+             style="opacity:0.10000598"><path
+               inkscape:connector-curvature="0"
+               d="m 1432.002,722 -374,0 0,-374 374,0 0,374 z m -3,-371 -368,0 0,368 368,0 0,-368 z"
+               id="path3094-1"
+               style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g><g
+         transform="translate(290.06807,8.3297801)"
+         id="g3096-6"><g
+           id="g3098-6" /><g
+           id="g3104-5"><g
+             clip-path="url(#clipPath3100-8-2)"
+             id="g3106-9"
+             style="opacity:0.10000598"><g
+               transform="translate(1434.334,317.334)"
+               id="g3108-9"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 -378.666,0 c -14.729,0 -26.666,11.938 -26.666,26.666 l 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 L 0,-5.334 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 C 26.668,11.938 14.729,0 0,0"
+                 id="path3110-8"
+                 style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g
+         transform="translate(290.06807,8.3297801)"
+         id="g3112-1"><g
+           id="g3114-5" /><g
+           id="g3120-7"><g
+             clip-path="url(#clipPath3116-4-9)"
+             id="g3122-5"
+             style="opacity:0.10000598"><g
+               transform="translate(1434.334,756)"
+               id="g3124-1"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 c 0,14.728 11.937,26.667 26.666,26.667 L 0,-5.333 c 14.729,0 26.668,-11.939 26.668,-26.667 l 0,5.333 C 26.668,-11.938 14.729,0 0,0"
+                 id="path3126-0"
+                 style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g></g><g
+     inkscape:groupmode="layer"
+     id="layer7"
+     inkscape:label="Layer4"
+     style="display:inline"
+     transform="translate(436.0495,72.4457)"><g
+       style="display:inline"
+       id="g3622-5-8"
+       transform="matrix(5.2235991,0,0,-5.1937884,507.13047,984.15494)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c -32.947,0 -59.75,26.804 -59.75,59.75 0,32.946 26.803,59.75 59.75,59.75 32.945,0 59.75,-26.804 59.75,-59.75 C 59.75,26.804 32.945,0 0,0"
+         style="fill:#ff4a3c;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3624-3-9" /></g><g
+       style="display:inline"
+       id="g3630-4-7"
+       transform="matrix(5.2235991,0,0,-5.1937884,-2762.8426,3436.9216)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3632-0-4"
+         clip-path="url(#clipPath3634-8-0)"><g
+           id="g3638-2-4"><g
+             id="g3640-4-1" /><g
+             id="g3666-9-6"><g
+               style="opacity:0.119995"
+               clip-path="url(#clipPath3642-3-4)"
+               id="g3668-8-7"><g
+                 id="g3670-0-5"><g
+                   id="g3672-4-4" /><g
+                   mask="url(#mask3650-5-0)"
+                   id="g3674-2-0"><g
+                     transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"
+                     id="g3676-6-2"><image
+                       width="1"
+                       height="1"
+                       transform="matrix(1,0,0,-1,0,1)"
+                       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAAASdJREFUeJzt1rFuwyAUQFGw/P+/TIfKamQ5be7kRjlnshEDw9WDudZa48Kc82qZD/Eki7GfF4TCGD8dnMPZzxvg0Tmc7c7D8D6OcLbHH/iLCcPL5pxjjjGun8NwwYQhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDIlgSARDIhgSwZAIhkQwJIIhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDIlgSARDIhgSwZAIhkQwJIIhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDMm21rr7DLyJtZYJQ7ON8V0O/OZoxIQh2Y+Po6A5522H4f853z77sw3C+WzPnilfB04mnX6avLgAAAAASUVORK5CYII="
+                       mask="url(#mask3662-9-4)"
+                       id="image3678-1-3" /></g></g></g></g></g></g><g
+           id="g3680-5-3"
+           transform="translate(689.7031,476.2588)"><path
+             inkscape:connector-curvature="0"
+             d="m 0,0 c 0,-1.642 -1.344,-2.984 -2.986,-2.984 l -121.434,0 c -1.643,0 -2.986,1.342 -2.986,2.984 l 0,60.719 c 0,1.641 1.343,2.985 2.986,2.985 l 121.434,0 C -1.344,63.704 0,62.36 0,60.719 L 0,0 z"
+             style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+             id="path3682-6-2" /></g></g></g><g
+       id="layer3"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         transform="matrix(1.25,0,0,-1.25,715.58308,453.4259)"
+         id="g3024-4"
+         style="fill:#000000;display:inline"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 -12.195,205.05 -307.49,0 L -331.88,0 c 44.595,34.886 102.563,58.974 165.94,58.974 C -102.563,58.974 -44.595,34.886 0,0"
+           id="path3026-3"
+           style="fill:#2e2e2e;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,300.90228,894.5124)"
+         id="g3028-0"
+         style="fill:#000000;display:inline"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 12.06,-202.039 307.49,0 L 331.609,0 C 287.033,-34.822 229.119,-58.869 165.805,-58.869 102.491,-58.869 44.576,-34.822 0,0"
+           id="path3030-8"
+           style="fill:#2e2e2e;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,456.87948,388.9154)"
+         id="g3032-2"
+         style="display:inline"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 c 5.706,1.02 11.485,1.83 17.328,2.423 3.895,0.395 7.819,0.694 11.769,0.895 3.95,0.2 7.926,0.301 11.926,0.301 4,0 7.976,-0.101 11.926,-0.301 3.95,-0.201 7.874,-0.5 11.77,-0.895 C 70.561,1.83 76.341,1.02 82.047,0 c 108.425,-19.367 190.726,-114.139 190.726,-228.132 0,-127.991 -103.756,-231.75 -231.75,-231.75 -127.99,0 -231.751,103.759 -231.751,231.75 0,113.993 82.305,208.765 190.728,228.132 m 41.023,26.794 c -140.792,0 -254.926,-114.133 -254.926,-254.926 0,-140.792 114.134,-254.926 254.926,-254.926 140.79,0 254.926,114.134 254.926,254.926 0,140.793 -114.136,254.926 -254.926,254.926"
+           id="path3034-1"
+           style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,508.15818,355.4224)"
+         id="g3036-8"
+         style="fill:#000000;display:inline"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 c -140.792,0 -254.926,-114.134 -254.926,-254.926 0,-140.792 114.134,-254.926 254.926,-254.926 140.792,0 254.926,114.134 254.926,254.926 C 254.926,-114.134 140.792,0 0,0 m 231.75,-254.926 c 0,-127.991 -103.758,-231.75 -231.75,-231.75 -127.992,0 -231.75,103.759 -231.75,231.75 0,127.993 103.758,231.751 231.75,231.751 127.992,0 231.75,-103.758 231.75,-231.751"
+           id="path3038-3"
+           style="fill:#2c2c2c;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,-264.34372,1339.588)"
+         id="g3040-9"
+         style="display:inline"><g
+           id="g3042-1" /><g
+           id="g3048-2"><g
+             clip-path="url(#clipPath3044-8-3-2)"
+             id="g3050-4"
+             style="opacity:0.10000598"><g
+               transform="translate(844.249,532.4062)"
+               id="g3052-7"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 c 0,-124.952 -101.295,-226.248 -226.248,-226.248 -124.952,0 -226.247,101.296 -226.247,226.248 0,124.953 101.295,226.248 226.247,226.248 C -101.295,226.248 0,124.953 0,0"
+                 id="path3054-5"
+                 style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g
+         transform="matrix(1.25,0,0,-1.25,-264.34372,1339.588)"
+         id="g3056-2"
+         style="display:inline"><g
+           id="g3058-6" /><g
+           id="g3064-1"><g
+             clip-path="url(#clipPath3060-8-2-1)"
+             id="g3066-2"
+             style="opacity:0.10000598"><g
+               transform="translate(618.0015,787.7266)"
+               id="g3068-5"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 c -34.466,0 -67.903,-6.75 -99.383,-20.065 -30.404,-12.861 -57.707,-31.269 -81.155,-54.716 -23.446,-23.447 -41.856,-50.752 -54.715,-81.156 -13.314,-31.48 -20.066,-64.916 -20.066,-99.383 0,-34.465 6.752,-67.904 20.066,-99.381 12.859,-30.405 31.269,-57.709 54.715,-81.156 23.448,-23.447 50.751,-41.857 81.155,-54.715 31.48,-13.315 64.917,-20.066 99.383,-20.066 34.466,0 67.903,6.751 99.382,20.066 30.405,12.858 57.708,31.268 81.155,54.715 23.447,23.447 41.857,50.751 54.716,81.156 13.314,31.477 20.066,64.916 20.066,99.381 0,34.467 -6.752,67.903 -20.066,99.383 -12.859,30.404 -31.269,57.709 -54.716,81.156 -23.447,23.447 -50.75,41.855 -81.155,54.716 C 67.903,-6.75 34.466,0 0,0 m 0,-3.153 c 139.268,0 252.167,-112.897 252.167,-252.167 0,-139.267 -112.899,-252.166 -252.167,-252.166 -139.268,0 -252.167,112.899 -252.167,252.166 0,139.27 112.899,252.167 252.167,252.167"
+                 id="path3070-2"
+                 style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g><g
+       style="display:inline"
+       id="g3692-7-8"
+       transform="matrix(5.2956158,0,0,-5.2956158,-2815.7539,3491.418)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3694-5-3" /><g
+         id="g3704-5-3"><g
+           clip-path="url(#clipPath3696-9-7-9)"
+           id="g3706-2-5"
+           style="opacity:0.5"><g
+             id="g3708-6-9"><g
+               clip-path="url(#clipPath3700-1-1-8)"
+               id="g3710-3-0"><path
+                 d="m 623.994,518.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z"
+                 style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path3712-4-5"
+                 inkscape:connector-curvature="0" /></g></g></g></g></g><path
+       d="m 584.03152,795.94967 -264.78075,0 0,-26.47808 264.78075,0 0,26.47808 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3714-2-5"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><path
+       d="m 462.23242,848.90583 -142.98165,0 0,-26.47808 142.98165,0 0,26.47808 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3716-3-1"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><g
+       style="display:inline"
+       id="g3718-7-1"
+       transform="matrix(5.2956158,0,0,-5.2956158,-2815.7539,3491.418)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3720-1-0" /><g
+         id="g3730-8-4"><g
+           clip-path="url(#clipPath3722-1-6-1)"
+           id="g3732-8-4"
+           style="opacity:0"><g
+             id="g3734-9-2"><g
+               clip-path="url(#clipPath3726-6-9-4)"
+               id="g3736-3-3"><path
+                 d="m 664.001,520 -12.001,0 0,12 12.001,0 0,-12 z"
+                 style="fill:#ee2a7b;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path3738-7-6"
+                 inkscape:connector-curvature="0" /></g></g></g></g></g><g
+       style="display:inline"
+       id="g3740-9-7"
+       transform="matrix(5.2956158,0,0,-5.2956158,644.93112,705.35546)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         d="m 0,0 4.5,0 0,-4.501 0.501,0 4,9.001 L 0,0.501 0,0 z"
+         style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3742-8-7"
+         inkscape:connector-curvature="0" /></g></g><g
+     inkscape:groupmode="layer"
+     id="layer6"
+     inkscape:label="Layer3"
+     style="display:inline"
+     transform="translate(436.0495,72.4457)"><g
+       style="display:inline"
+       id="g3508-5-6"
+       transform="matrix(5.09,0,0,-5.09,742.55563,925.70096)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c -2.209,0 -4,1.791 -4,4 l 0,92 c 0,2.209 1.791,4 4,4 l 92,0 c 2.209,0 4,-1.791 4,-4 L 96,4 C 96,1.791 94.209,0 92,0 L 0,0 z"
+         style="fill:#9d65dc;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3510-0-8" /></g><g
+       style="display:inline"
+       id="g3516-7-9"
+       transform="matrix(5.09,0,0,-5.09,-2642.2948,3424.8908)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3518-2-7" /><g
+         id="g3544-9-6"><g
+           style="opacity:0.119995"
+           clip-path="url(#clipPath3520-6-0)"
+           id="g3546-7-3"><g
+             id="g3548-8-7"><g
+               id="g3550-3-6" /><g
+               mask="url(#mask3528-3-8)"
+               id="g3552-8-7"><g
+                 transform="matrix(93,0,0,68,667,493)"
+                 id="g3554-9-9"><image
+                   width="1"
+                   height="1"
+                   transform="matrix(1,0,0,-1,0,1)"
+                   xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAAP1JREFUeJzt3DGKhEAARcFWvP+VeyNBxJGFHX3BVmU2BvL4DBP1Muec48KyLFfH/NKHrGOMMbbzgdjfsXe8ir+dX+K7ruKv1cf8N8dRr+cDnmfpL9rHvVr5+yw9sIwxPv+h5BGWHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9JfNOUUvrHe3H/MMS3/RPvD1+MA7LP0lx2Fv50N3737X7aX155fE/5u7n+wfv04ph+lQnM8AAAAASUVORK5CYII="
+                   mask="url(#mask3540-4-8)"
+                   id="image3556-9-8" /></g></g></g></g></g></g><g
+       style="display:inline"
+       id="g3558-6-7"
+       transform="matrix(5.09,0,0,-5.09,1180.2956,859.53096)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c 0,-1.65 -1.35,-3 -3,-3 l -74,0 c -1.649,0 -3,1.35 -3,3 l 0,50 c 0,1.65 1.351,3 3,3 l 74,0 c 1.65,0 3,-1.35 3,-3 L 0,0 z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3560-5-9" /></g><g
+       style="display:inline"
+       id="g3562-4-5"
+       transform="matrix(5.09,0,0,-5.09,-2642.2948,3424.8908)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3564-6-8" /><g
+         id="g3574-7-5"><g
+           style="opacity:0.5"
+           clip-path="url(#clipPath3566-8-1)"
+           id="g3576-7-7"><g
+             id="g3578-2-1"><g
+               clip-path="url(#clipPath3570-6-5)"
+               id="g3580-1-1"><path
+                 inkscape:connector-curvature="0"
+                 d="m 710.994,535.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z"
+                 style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path3582-0-1" /></g></g></g></g></g><path
+       inkscape:connector-curvature="0"
+       d="m 1068.3156,747.55096 -254.49997,0 0,-25.45 254.49997,0 0,25.45 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3584-1-4"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><path
+       inkscape:connector-curvature="0"
+       d="m 951.24563,798.45096 -137.43,0 0,-25.45 137.43,0 0,25.45 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3586-5-3"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><g
+       style="display:inline"
+       id="g3588-5-2"
+       transform="matrix(5.09,0,0,-5.09,-2642.2948,3424.8908)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3590-3-5" /><g
+         id="g3596-7-7"><g
+           style="opacity:0"
+           clip-path="url(#clipPath3592-5-6)"
+           id="g3598-6-3"><path
+             inkscape:connector-curvature="0"
+             d="m 730.777,537 12,0 0,12 -12,0 0,-12 z"
+             style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+             id="path3600-8-8" /></g></g></g><g
+       style="display:inline"
+       id="g3602-7-1"
+       transform="matrix(5.09,0,0,-5.09,1133.3524,659.74846)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c 0,0.414 -0.336,0.75 -0.75,0.75 l -2.75,0 -2.5,4 -1,0 1.25,-4 -2.75,0 -0.75,1 -0.75,0 0.5,-1.75 -0.5,-1.75 0.75,0 0.75,1 2.75,0 -1.25,-4 1,0 2.5,4 2.75,0 C -0.336,-0.75 0,-0.414 0,0"
+         style="fill:#00c853;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3604-3-1" /></g><g
+       id="layer2"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         transform="matrix(1.25,0,0,-1.25,1156.7381,197.1134)"
+         id="g3072-2"
+         style="fill:#4d4d4d;display:inline"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 -285.486,0 -14,-190.491 313.486,0 L 0,0 z"
+           id="path3074-4"
+           style="fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,1174.2381,908.94815)"
+         id="g3076-2"
+         style="fill:#333333;display:inline"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 -313.486,0 14,-190.491 286.486,0 L 0,0 z"
+           id="path3078-2"
+           style="fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><path
+         inkscape:connector-curvature="0"
+         d="m 1210.8105,905.83777 -467.50004,0 0,-467.5 467.50004,0 0,467.5 z m 4.165,-511.25 -473.33254,0 c -18.41125,0 -33.3325,14.92251 -33.3325,33.33376 l 0,6.66624 0,475 0,6.66751 c 0,18.40874 14.92125,33.33249 33.3325,33.33249 l 473.33254,0 c 18.4112,0 33.335,-14.92375 33.335,-33.33249 l 0,-6.66751 0,-475 0,-6.66624 c 0,-18.41125 -14.9238,-33.33376 -33.335,-33.33376"
+         id="path3080-8"
+         style="fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" /><g
+         transform="matrix(1.25,0,0,-1.25,-577.94194,1339.5878)"
+         id="g3082-6"
+         style="display:inline"><g
+           id="g3084-6" /><g
+           id="g3090-6"><g
+             clip-path="url(#clipPath3086-0-0-4)"
+             id="g3092-6"
+             style="opacity:0.10000598"><path
+               inkscape:connector-curvature="0"
+               d="m 1432.002,722 -374,0 0,-374 374,0 0,374 z m -3,-371 -368,0 0,368 368,0 0,-368 z"
+               id="path3094-4"
+               style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g><g
+         transform="matrix(1.25,0,0,-1.25,-577.94194,1339.5878)"
+         id="g3096-1"
+         style="display:inline"><g
+           id="g3098-7" /><g
+           id="g3104-3"><g
+             clip-path="url(#clipPath3100-0-7-1)"
+             id="g3106-8"
+             style="opacity:0.10000598"><g
+               transform="translate(1434.334,317.334)"
+               id="g3108-5"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 -378.666,0 c -14.729,0 -26.666,11.938 -26.666,26.666 l 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 L 0,-5.334 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 C 26.668,11.938 14.729,0 0,0"
+                 id="path3110-7"
+                 style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g
+         transform="matrix(1.25,0,0,-1.25,-577.94194,1339.5878)"
+         id="g3112-0"
+         style="display:inline"><g
+           id="g3114-4" /><g
+           id="g3120-4"><g
+             clip-path="url(#clipPath3116-3-2-9)"
+             id="g3122-9"
+             style="opacity:0.10000598"><g
+               transform="translate(1434.334,756)"
+               id="g3124-5"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 c 0,14.728 11.937,26.667 26.666,26.667 L 0,-5.333 c 14.729,0 26.668,-11.939 26.668,-26.667 l 0,5.333 C 26.668,-11.938 14.729,0 0,0"
+                 id="path3126-3"
+                 style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g></g><g
+     inkscape:groupmode="layer"
+     id="layer5"
+     inkscape:label="Layer2"
+     style="display:inline"
+     transform="translate(436.0495,72.4457)"><g
+       style="display:inline"
+       id="g3622-5"
+       transform="matrix(5.2235991,0,0,-5.1937884,1450.0328,987.05631)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c -32.947,0 -59.75,26.804 -59.75,59.75 0,32.946 26.803,59.75 59.75,59.75 32.945,0 59.75,-26.804 59.75,-59.75 C 59.75,26.804 32.945,0 0,0"
+         style="fill:#0bda2f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3624-3" /></g><g
+       style="display:inline"
+       id="g3630-4"
+       transform="matrix(5.2235991,0,0,-5.1937884,-1819.9402,3439.8229)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3632-0"
+         clip-path="url(#clipPath3634-8)"><g
+           id="g3638-2"><g
+             id="g3640-4" /><g
+             id="g3666-9"><g
+               style="opacity:0.119995"
+               clip-path="url(#clipPath3642-3)"
+               id="g3668-8"><g
+                 id="g3670-0"><g
+                   id="g3672-4" /><g
+                   mask="url(#mask3650-5)"
+                   id="g3674-2"><g
+                     transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"
+                     id="g3676-6"><image
+                       width="1"
+                       height="1"
+                       transform="matrix(1,0,0,-1,0,1)"
+                       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAAASdJREFUeJzt1rFuwyAUQFGw/P+/TIfKamQ5be7kRjlnshEDw9WDudZa48Kc82qZD/Eki7GfF4TCGD8dnMPZzxvg0Tmc7c7D8D6OcLbHH/iLCcPL5pxjjjGun8NwwYQhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDIlgSARDIhgSwZAIhkQwJIIhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDIlgSARDIhgSwZAIhkQwJIIhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDMm21rr7DLyJtZYJQ7ON8V0O/OZoxIQh2Y+Po6A5522H4f853z77sw3C+WzPnilfB04mnX6avLgAAAAASUVORK5CYII="
+                       mask="url(#mask3662-9)"
+                       id="image3678-1" /></g></g></g></g></g></g><g
+           id="g3680-5"
+           transform="translate(689.7031,476.2588)"><path
+             inkscape:connector-curvature="0"
+             d="m 0,0 c 0,-1.642 -1.344,-2.984 -2.986,-2.984 l -121.434,0 c -1.643,0 -2.986,1.342 -2.986,2.984 l 0,60.719 c 0,1.641 1.343,2.985 2.986,2.985 l 121.434,0 C -1.344,63.704 0,62.36 0,60.719 L 0,0 z"
+             style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+             id="path3682-6" /></g></g></g><g
+       transform="translate(2e-5,-3e-5)"
+       id="layer1"
+       style="display:inline"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         transform="matrix(1.25,0,0,-1.25,1656.802,453.73263)"
+         id="g3024"
+         style="fill:#000000"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 -12.195,205.05 -307.49,0 L -331.88,0 c 44.595,34.886 102.563,58.974 165.94,58.974 C -102.563,58.974 -44.595,34.886 0,0"
+           id="path3026"
+           style="fill:#606060;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,1242.1212,894.81914)"
+         id="g3028"
+         style="fill:#000000"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 12.06,-202.039 307.49,0 L 331.609,0 C 287.033,-34.822 229.119,-58.869 165.805,-58.869 102.491,-58.869 44.576,-34.822 0,0"
+           id="path3030"
+           style="fill:#606060;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,1398.0984,389.22214)"
+         id="g3032"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 c 5.706,1.02 11.485,1.83 17.328,2.423 3.895,0.395 7.819,0.694 11.769,0.895 3.95,0.2 7.926,0.301 11.926,0.301 4,0 7.976,-0.101 11.926,-0.301 3.95,-0.201 7.874,-0.5 11.77,-0.895 C 70.561,1.83 76.341,1.02 82.047,0 c 108.425,-19.367 190.726,-114.139 190.726,-228.132 0,-127.991 -103.756,-231.75 -231.75,-231.75 -127.99,0 -231.751,103.759 -231.751,231.75 0,113.993 82.305,208.765 190.728,228.132 m 41.023,26.794 c -140.792,0 -254.926,-114.133 -254.926,-254.926 0,-140.792 114.134,-254.926 254.926,-254.926 140.79,0 254.926,114.134 254.926,254.926 0,140.793 -114.136,254.926 -254.926,254.926"
+           id="path3034"
+           style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,1449.3771,355.72914)"
+         id="g3036"
+         style="fill:#000000"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 c -140.792,0 -254.926,-114.134 -254.926,-254.926 0,-140.792 114.134,-254.926 254.926,-254.926 140.792,0 254.926,114.134 254.926,254.926 C 254.926,-114.134 140.792,0 0,0 m 231.75,-254.926 c 0,-127.991 -103.758,-231.75 -231.75,-231.75 -127.992,0 -231.75,103.759 -231.75,231.75 0,127.993 103.758,231.751 231.75,231.751 127.992,0 231.75,-103.758 231.75,-231.751"
+           id="path3038"
+           style="fill:#606060;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="matrix(1.25,0,0,-1.25,676.87523,1339.8947)"
+         id="g3040"><g
+           id="g3042" /><g
+           id="g3048"><g
+             clip-path="url(#clipPath3044-8-1)"
+             id="g3050"
+             style="opacity:0.10000598"><g
+               transform="translate(844.249,532.4062)"
+               id="g3052"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 c 0,-124.952 -101.295,-226.248 -226.248,-226.248 -124.952,0 -226.247,101.296 -226.247,226.248 0,124.953 101.295,226.248 226.247,226.248 C -101.295,226.248 0,124.953 0,0"
+                 id="path3054"
+                 style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g
+         transform="matrix(1.25,0,0,-1.25,676.87523,1339.8947)"
+         id="g3056"><g
+           id="g3058" /><g
+           id="g3064"><g
+             clip-path="url(#clipPath3060-8-27)"
+             id="g3066"
+             style="opacity:0.10000598"><g
+               transform="translate(618.0015,787.7266)"
+               id="g3068"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 c -34.466,0 -67.903,-6.75 -99.383,-20.065 -30.404,-12.861 -57.707,-31.269 -81.155,-54.716 -23.446,-23.447 -41.856,-50.752 -54.715,-81.156 -13.314,-31.48 -20.066,-64.916 -20.066,-99.383 0,-34.465 6.752,-67.904 20.066,-99.381 12.859,-30.405 31.269,-57.709 54.715,-81.156 23.448,-23.447 50.751,-41.857 81.155,-54.715 31.48,-13.315 64.917,-20.066 99.383,-20.066 34.466,0 67.903,6.751 99.382,20.066 30.405,12.858 57.708,31.268 81.155,54.715 23.447,23.447 41.857,50.751 54.716,81.156 13.314,31.477 20.066,64.916 20.066,99.381 0,34.467 -6.752,67.903 -20.066,99.383 -12.859,30.404 -31.269,57.709 -54.716,81.156 -23.447,23.447 -50.75,41.855 -81.155,54.716 C 67.903,-6.75 34.466,0 0,0 m 0,-3.153 c 139.268,0 252.167,-112.897 252.167,-252.167 0,-139.267 -112.899,-252.166 -252.167,-252.166 -139.268,0 -252.167,112.899 -252.167,252.166 0,139.27 112.899,252.167 252.167,252.167"
+                 id="path3070"
+                 style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g><g
+       style="display:inline"
+       id="g3692-7"
+       transform="matrix(5.2956158,0,0,-5.2956158,-1870.725,3488.2105)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3694-5" /><g
+         id="g3704-5"><g
+           clip-path="url(#clipPath3696-9-7)"
+           id="g3706-2"
+           style="opacity:0.5"><g
+             id="g3708-6"><g
+               clip-path="url(#clipPath3700-1-1)"
+               id="g3710-3"><path
+                 d="m 623.994,518.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z"
+                 style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path3712-4"
+                 inkscape:connector-curvature="0" /></g></g></g></g></g><path
+       d="m 1529.0604,792.7421 -264.7808,0 0,-26.47808 264.7808,0 0,26.47808 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3714-2"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><path
+       d="m 1407.2613,845.69826 -142.9817,0 0,-26.47808 142.9817,0 0,26.47808 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3716-3"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><g
+       style="display:inline"
+       id="g3718-7"
+       transform="matrix(5.2956158,0,0,-5.2956158,-1870.725,3488.2105)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3720-1" /><g
+         id="g3730-8"><g
+           clip-path="url(#clipPath3722-1-6)"
+           id="g3732-8"
+           style="opacity:0"><g
+             id="g3734-9"><g
+               clip-path="url(#clipPath3726-6-9)"
+               id="g3736-3"><path
+                 d="m 664.001,520 -12.001,0 0,12 12.001,0 0,-12 z"
+                 style="fill:#ee2a7b;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path3738-7"
+                 inkscape:connector-curvature="0" /></g></g></g></g></g><g
+       style="display:inline"
+       id="g3740-9"
+       transform="matrix(5.2956158,0,0,-5.2956158,1589.96,702.14789)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         d="m 0,0 4.5,0 0,-4.501 0.501,0 4,9.001 L 0,0.501 0,0 z"
+         style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3742-8"
+         inkscape:connector-curvature="0" /></g></g><g
+     inkscape:groupmode="layer"
+     id="layer4"
+     inkscape:label="Layer1"
+     style="display:inline"
+     transform="translate(436.0495,72.4457)"><g
+       style="display:inline"
+       id="g3508-5"
+       transform="matrix(5.09,0,0,-5.09,1683.0619,927.12472)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c -2.209,0 -4,1.791 -4,4 l 0,92 c 0,2.209 1.791,4 4,4 l 92,0 c 2.209,0 4,-1.791 4,-4 L 96,4 C 96,1.791 94.209,0 92,0 L 0,0 z"
+         style="fill:#ffed0d;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3510-0" /></g><g
+       style="display:inline"
+       id="g3516-7"
+       transform="matrix(5.09,0,0,-5.09,-1701.7885,3426.3146)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3518-2" /><g
+         id="g3544-9"><g
+           style="opacity:0.119995"
+           clip-path="url(#clipPath3520-6)"
+           id="g3546-7"><g
+             id="g3548-8"><g
+               id="g3550-3" /><g
+               mask="url(#mask3528-3)"
+               id="g3552-8"><g
+                 transform="matrix(93,0,0,68,667,493)"
+                 id="g3554-9"><image
+                   width="1"
+                   height="1"
+                   transform="matrix(1,0,0,-1,0,1)"
+                   xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAAP1JREFUeJzt3DGKhEAARcFWvP+VeyNBxJGFHX3BVmU2BvL4DBP1Muec48KyLFfH/NKHrGOMMbbzgdjfsXe8ir+dX+K7ruKv1cf8N8dRr+cDnmfpL9rHvVr5+yw9sIwxPv+h5BGWHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9JfNOUUvrHe3H/MMS3/RPvD1+MA7LP0lx2Fv50N3737X7aX155fE/5u7n+wfv04ph+lQnM8AAAAASUVORK5CYII="
+                   mask="url(#mask3540-4)"
+                   id="image3556-9" /></g></g></g></g></g></g><g
+       style="display:inline"
+       id="g3558-6"
+       transform="matrix(5.09,0,0,-5.09,2120.8019,860.95472)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c 0,-1.65 -1.35,-3 -3,-3 l -74,0 c -1.649,0 -3,1.35 -3,3 l 0,50 c 0,1.65 1.351,3 3,3 l 74,0 c 1.65,0 3,-1.35 3,-3 L 0,0 z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3560-5" /></g><g
+       style="display:inline"
+       id="g3562-4"
+       transform="matrix(5.09,0,0,-5.09,-1701.7885,3426.3146)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3564-6" /><g
+         id="g3574-7"><g
+           style="opacity:0.5"
+           clip-path="url(#clipPath3566-8)"
+           id="g3576-7"><g
+             id="g3578-2"><g
+               clip-path="url(#clipPath3570-6)"
+               id="g3580-1"><path
+                 inkscape:connector-curvature="0"
+                 d="m 710.994,535.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z"
+                 style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none"
+                 id="path3582-0" /></g></g></g></g></g><path
+       inkscape:connector-curvature="0"
+       d="m 2008.8219,748.97472 -254.5,0 0,-25.45 254.5,0 0,25.45 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3584-1"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><path
+       inkscape:connector-curvature="0"
+       d="m 1891.7519,799.87472 -137.43,0 0,-25.45 137.43,0 0,25.45 z"
+       style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline"
+       id="path3586-5"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999" /><g
+       style="display:inline"
+       id="g3588-5"
+       transform="matrix(5.09,0,0,-5.09,-1701.7885,3426.3146)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><g
+         id="g3590-3" /><g
+         id="g3596-7"><g
+           style="opacity:0"
+           clip-path="url(#clipPath3592-5)"
+           id="g3598-6"><path
+             inkscape:connector-curvature="0"
+             d="m 730.777,537 12,0 0,12 -12,0 0,-12 z"
+             style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+             id="path3600-8" /></g></g></g><g
+       style="display:inline"
+       id="g3602-7"
+       transform="matrix(5.09,0,0,-5.09,2073.8587,661.17222)"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"><path
+         inkscape:connector-curvature="0"
+         d="m 0,0 c 0,0.414 -0.336,0.75 -0.75,0.75 l -2.75,0 -2.5,4 -1,0 1.25,-4 -2.75,0 -0.75,1 -0.75,0 0.5,-1.75 -0.5,-1.75 0.75,0 0.75,1 2.75,0 -1.25,-4 1,0 2.5,4 2.75,0 C -0.336,-0.75 0,-0.414 0,0"
+         style="fill:#00c853;fill-opacity:1;fill-rule:nonzero;stroke:none"
+         id="path3604-3" /></g><g
+       transform="matrix(1.25,0,0,-1.25,0,1350)"
+       id="g3012"
+       style="display:inline"
+       inkscape:export-xdpi="18.559999"
+       inkscape:export-ydpi="18.559999"
+       inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"><g
+         transform="translate(1677.8121,922.30928)"
+         id="g3072"
+         style="fill:#333333;fill-opacity:1"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 -285.486,0 -14,-190.491 313.486,0 L 0,0 z"
+           id="path3074"
+           style="fill:#747474;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g
+         transform="translate(1691.8121,352.84148)"
+         id="g3076"
+         style="fill:#333333;fill-opacity:1"><path
+           inkscape:connector-curvature="0"
+           d="m 0,0 -313.486,0 14,-190.491 286.486,0 L 0,0 z"
+           id="path3078"
+           style="fill:#747474;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><path
+         inkscape:connector-curvature="0"
+         d="m 1721.07,355.32978 -374,0 0,374 374,0 0,-374 z m 3.332,409 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 0,-380 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 l 378.666,0 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 0,380 0,5.333 c 0,14.729 -11.939,26.667 -26.668,26.667"
+         id="path3080"
+         style="fill:#747474;fill-opacity:1;fill-rule:nonzero;stroke:none" /><g
+         transform="translate(290.06807,8.3297801)"
+         id="g3082"><g
+           id="g3084" /><g
+           id="g3090"><g
+             clip-path="url(#clipPath3086-4)"
+             id="g3092"
+             style="opacity:0.10000598"><path
+               inkscape:connector-curvature="0"
+               d="m 1432.002,722 -374,0 0,-374 374,0 0,374 z m -3,-371 -368,0 0,368 368,0 0,-368 z"
+               id="path3094"
+               style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g><g
+         transform="translate(290.06807,8.3297801)"
+         id="g3096"><g
+           id="g3098" /><g
+           id="g3104"><g
+             clip-path="url(#clipPath3100-8)"
+             id="g3106"
+             style="opacity:0.10000598"><g
+               transform="translate(1434.334,317.334)"
+               id="g3108"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 -378.666,0 c -14.729,0 -26.666,11.938 -26.666,26.666 l 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 L 0,-5.334 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 C 26.668,11.938 14.729,0 0,0"
+                 id="path3110"
+                 style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g
+         transform="translate(290.06807,8.3297801)"
+         id="g3112"><g
+           id="g3114" /><g
+           id="g3120"><g
+             clip-path="url(#clipPath3116-4)"
+             id="g3122"
+             style="opacity:0.10000598"><g
+               transform="translate(1434.334,756)"
+               id="g3124"><path
+                 inkscape:connector-curvature="0"
+                 d="m 0,0 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 c 0,14.728 11.937,26.667 26.666,26.667 L 0,-5.333 c 14.729,0 26.668,-11.939 26.668,-26.667 l 0,5.333 C 26.668,-11.938 14.729,0 0,0"
+                 id="path3126"
+                 style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g><g
+       id="g3744"
+       transform="matrix(1.25,0,0,-1.25,-298.02174,762.5543)"><g
+         id="g3746" /><g
+         id="g3752"><g
+           clip-path="url(#clipPath3748-6)"
+           id="g3754"
+           style="opacity:0"><path
+             d="m 1484,446 -270,0 0,182 270,0 0,-182 z"
+             style="fill:#ec008c;fill-opacity:1;fill-rule:nonzero;stroke:none"
+             id="path3756"
+             inkscape:connector-curvature="0" /></g></g></g><g
+       id="g3758"
+       transform="matrix(1.25,0,0,-1.25,1378.2283,155.0543)" /><g
+       id="g3762"
+       transform="matrix(1.25,0,0,-1.25,1539.4783,28.8043)" /></g></svg>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index bec1d38..1fac5b6 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1058,54 +1058,72 @@
         final Drawable drawable;
 
         final String name = parser.getName();
-        if (name.equals("selector")) {
-            drawable = new StateListDrawable();
-        } else if (name.equals("animated-selector")) {
-            drawable = new AnimatedStateListDrawable();
-        } else if (name.equals("level-list")) {
-            drawable = new LevelListDrawable();
-        } else if (name.equals("layer-list")) {
-            drawable = new LayerDrawable();
-        } else if (name.equals("transition")) {
-            drawable = new TransitionDrawable();
-        } else if (name.equals("ripple")) {
-            drawable = new RippleDrawable();
-        } else if (name.equals("color")) {
-            drawable = new ColorDrawable();
-        } else if (name.equals("shape")) {
-            drawable = new GradientDrawable();
-        } else if (name.equals("vector")) {
-            drawable = new VectorDrawable();
-        } else if (name.equals("animated-vector")) {
-            drawable = new AnimatedVectorDrawable();
-        } else if (name.equals("scale")) {
-            drawable = new ScaleDrawable();
-        } else if (name.equals("clip")) {
-            drawable = new ClipDrawable();
-        } else if (name.equals("rotate")) {
-            drawable = new RotateDrawable();
-        } else if (name.equals("animated-rotate")) {
-            drawable = new AnimatedRotateDrawable();
-        } else if (name.equals("animation-list")) {
-            drawable = new AnimationDrawable();
-        } else if (name.equals("inset")) {
-            drawable = new InsetDrawable();
-        } else if (name.equals("bitmap")) {
-            //noinspection deprecation
-            drawable = new BitmapDrawable(r);
-            if (r != null) {
-               ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
-            }
-        } else if (name.equals("nine-patch")) {
-            drawable = new NinePatchDrawable();
-            if (r != null) {
-                ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
-             }
-        } else {
-            throw new XmlPullParserException(parser.getPositionDescription() +
-                    ": invalid drawable tag " + name);
-        }
+        switch (name) {
+            case "selector":
+                drawable = new StateListDrawable();
+                break;
+            case "animated-selector":
+                drawable = new AnimatedStateListDrawable();
+                break;
+            case "level-list":
+                drawable = new LevelListDrawable();
+                break;
+            case "layer-list":
+                drawable = new LayerDrawable();
+                break;
+            case "transition":
+                drawable = new TransitionDrawable();
+                break;
+            case "ripple":
+                drawable = new RippleDrawable();
+                break;
+            case "color":
+                drawable = new ColorDrawable();
+                break;
+            case "shape":
+                drawable = new GradientDrawable();
+                break;
+            case "vector":
+                drawable = new VectorDrawable();
+                break;
+            case "animated-vector":
+                drawable = new AnimatedVectorDrawable();
+                break;
+            case "scale":
+                drawable = new ScaleDrawable();
+                break;
+            case "clip":
+                drawable = new ClipDrawable();
+                break;
+            case "rotate":
+                drawable = new RotateDrawable();
+                break;
+            case "animated-rotate":
+                drawable = new AnimatedRotateDrawable();
+                break;
+            case "animation-list":
+                drawable = new AnimationDrawable();
+                break;
+            case "inset":
+                drawable = new InsetDrawable();
+                break;
+            case "bitmap":
+                drawable = new BitmapDrawable(r);
+                if (r != null) {
+                    ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
+                }
+                break;
+            case "nine-patch":
+                drawable = new NinePatchDrawable();
+                if (r != null) {
+                    ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());
+                }
+                break;
+            default:
+                throw new XmlPullParserException(parser.getPositionDescription() +
+                        ": invalid drawable tag " + name);
 
+        }
         drawable.inflate(r, parser, attrs, theme);
         return drawable;
     }
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 70ff6e5..40cd13e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -296,6 +296,9 @@
                 mStagingDisplayListData->children()[i]->mRenderNode->incParentRefCount();
             }
         }
+        // Damage with the old display list first then the new one to catch any
+        // changes in isRenderable or, in the future, bounds
+        damageSelf(info);
         deleteDisplayListData();
         mDisplayListData = mStagingDisplayListData;
         mStagingDisplayListData = NULL;
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 819affc..5d5ea02 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -332,8 +332,13 @@
         }
 
         /**
-         * Sends the change on the track information. This is expected to be called whenever a track
-         * is added/removed and the metadata of a track is modified.
+         * Sends the list of all audio/video/subtitle tracks. The is used by the framework to
+         * maintain the track information for a given session, which in turn is used by
+         * {@link TvView#getTracks} for the application to retrieve metadata for a given track type.
+         * The TV input service must call this method as soon as the track information becomes
+         * available or is updated. Note that in a case where a part of the information for a
+         * certain track is updated, it is not necessary to create a new {@link TvTrackInfo} object
+         * with a different track ID.
          *
          * @param tracks A list which includes track information.
          * @throws IllegalArgumentException if {@code tracks} contains redundant tracks.
@@ -364,8 +369,12 @@
         }
 
         /**
-         * Sends the ID of the selected track for a given track type. This is expected to be called
-         * whenever there is a change on track selection.
+         * Sends the type and ID of a selected track. This is used to inform the application that a
+         * specific track is selected. The TV input service must call this method as soon as a track
+         * is selected either by default or in response to a call to {@link #onSelectTrack}. The
+         * selected track ID for a given type is maintained in the framework until the next call to
+         * this method even after the entire track list is updated (but is reset when the session is
+         * tuned to a new channel), so care must be taken not to result in an obsolete track ID.
          *
          * @param type The type of the selected track. The type can be
          *            {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
deleted file mode 100644
index b0bc5d4..0000000
--- a/media/tests/omxjpegdecoder/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        omx_jpeg_decoder.cpp \
-        jpeg_decoder_bench.cpp \
-        StreamSource.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libskia \
-    libstagefright \
-    libstagefright_foundation \
-    libbinder \
-    libutils \
-    liblog \
-    libjpeg
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/external/jpeg \
-    $(TOP)/frameworks/base/media/libstagefright \
-    $(TOP)/frameworks/base/include/ \
-    $(TOP)/frameworks/base/ \
-    $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_MODULE := jpeg_bench
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/tests/omxjpegdecoder/StreamSource.cpp b/media/tests/omxjpegdecoder/StreamSource.cpp
deleted file mode 100644
index f764121a..0000000
--- a/media/tests/omxjpegdecoder/StreamSource.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * 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.
- */
-
-#include <media/stagefright/foundation/ADebug.h>
-
-#include "StreamSource.h"
-
-namespace android {
-
-StreamSource::StreamSource(SkStream *stream)
-        : mStream(stream) {
-    CHECK(stream != NULL);
-    mSize = stream->getLength();
-}
-
-StreamSource::~StreamSource() {
-    delete mStream;
-    mStream = NULL;
-}
-
-status_t StreamSource::initCheck() const {
-    return mStream != NULL ? OK : NO_INIT;
-}
-
-ssize_t StreamSource::readAt(off64_t offset, void *data, size_t size) {
-    Mutex::Autolock autoLock(mLock);
-
-    mStream->rewind();
-    mStream->skip(offset);
-    ssize_t result = mStream->read(data, size);
-
-    return result;
-}
-
-status_t StreamSource::getSize(off64_t *size) {
-      *size = mSize;
-      return OK;
-}
-
-}  // namespace android
diff --git a/media/tests/omxjpegdecoder/StreamSource.h b/media/tests/omxjpegdecoder/StreamSource.h
deleted file mode 100644
index 9807385..0000000
--- a/media/tests/omxjpegdecoder/StreamSource.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef STREAM_SOURCE_H_
-
-#define STREAM_SOURCE_H_
-
-#include <stdio.h>
-
-#include <SkStream.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class StreamSource : public DataSource {
-public:
-    // Pass the ownership of SkStream to StreamSource.
-    StreamSource(SkStream *SkStream);
-    virtual status_t initCheck() const;
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-    virtual status_t getSize(off64_t *size);
-
-protected:
-    virtual ~StreamSource();
-
-private:
-    SkStream *mStream;
-    size_t mSize;
-    Mutex mLock;
-
-    StreamSource(const StreamSource &);
-    StreamSource &operator=(const StreamSource &);
-};
-
-}  // namespace android
-
-#endif  // STREAM_SOURCE_H_
diff --git a/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp b/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp
deleted file mode 100644
index de6294d..0000000
--- a/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * 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.
- */
-
-#define LOG_TAG "OmxJpegDecoder"
-#include <sys/time.h>
-#include <utils/Log.h>
-
-#include <binder/ProcessState.h>
-
-#include "SkBitmap.h"
-#include "SkImageDecoder.h"
-#include "SkStream.h"
-#include "omx_jpeg_decoder.h"
-
-class SkJPEGImageDecoder : public SkImageDecoder {
-public:
-    virtual Format getFormat() const {
-        return kJPEG_Format;
-    }
-
-protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
-};
-
-int nullObjectReturn(const char msg[]) {
-    if (msg) {
-        SkDebugf("--- %s\n", msg);
-    }
-    return -1;
-}
-
-static int64_t getNowUs() {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-
-    return tv.tv_usec + (int64_t) tv.tv_sec * 1000000;
-}
-
-int testDecodeBounds(SkImageDecoder* decoder, SkStream* stream,
-        SkBitmap* bitmap) {
-    int64_t startTime = getNowUs();
-    SkColorType prefColorType = kN32_SkColorType;
-    SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodeBounds_Mode;
-
-    // Decode the input stream and then use the bitmap.
-    if (!decoder->decode(stream, bitmap, prefColorType, decodeMode)) {
-        return nullObjectReturn("decoder->decode returned false");
-    } else {
-        int64_t delay = getNowUs() - startTime;
-        printf("WidthxHeight: %dx%d\n", bitmap->width(), bitmap->height());
-        printf("Decoding Time in BoundsMode %.1f msec.\n", delay / 1000.0f);
-        return 0;
-    }
-}
-
-int testDecodePixels(SkImageDecoder* decoder, SkStream* stream,
-        SkBitmap* bitmap) {
-    int64_t startTime = getNowUs();
-    SkColorType prefColorType = kN32_SkColorType;
-    SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodePixels_Mode;
-
-    // Decode the input stream and then use the bitmap.
-    if (!decoder->decode(stream, bitmap, prefColorType, decodeMode)) {
-        return nullObjectReturn("decoder->decode returned false");
-    } else {
-        int64_t delay = getNowUs() - startTime;
-        printf("Decoding Time in PixelsMode %.1f msec.\n", delay / 1000.0f);
-        const char* filename = "/sdcard/omxJpegDecodedBitmap.rgba";
-        return storeBitmapToFile(bitmap, filename);
-    }
-}
-
-int testDecoder(SkImageDecoder* decoder, char* filename) {
-    // test DecodeMode == Pixels
-    SkStream* stream = new SkFILEStream(filename);
-    SkBitmap* bitmap = new SkBitmap;
-    testDecodePixels(decoder, stream, bitmap);
-    delete bitmap;
-
-    // test DecodeMode == Bounds
-    stream = new SkFILEStream(filename);
-    bitmap = new SkBitmap;
-    testDecodeBounds(decoder, stream, bitmap);
-    delete bitmap;
-
-    delete decoder;
-    return 0;
-}
-
-int main(int argc, char** argv) {
-    android::ProcessState::self()->startThreadPool();
-
-    printf("Decoding jpeg with libjpeg...\n");
-    SkJPEGImageDecoder* libjpeg = new SkJPEGImageDecoder;
-    testDecoder(libjpeg, argv[1]);
-
-    printf("\nDecoding jpeg with OMX...\n");
-    OmxJpegImageDecoder* omx = new OmxJpegImageDecoder;
-    testDecoder(omx, argv[1]);
-    return 0;
-}
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
deleted file mode 100644
index 229bfdb..0000000
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * 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.
- */
-
-#define LOG_TAG "OmxJpegDecoder"
-#include <sys/time.h>
-#include <utils/Log.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <media/IMediaPlayerService.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <SkImage.h>
-#include <SkMallocPixelRef.h>
-
-#include "omx_jpeg_decoder.h"
-#include "StreamSource.h"
-
-using namespace android;
-
-static void getJpegOutput(MediaBuffer* buffer, const char* filename) {
-    int size = buffer->range_length();
-    int offset = buffer->range_offset();
-    FILE *pFile = fopen(filename, "w+");
-
-    if (pFile == NULL) {
-        printf("Error: cannot open %s.\n", filename);
-    } else {
-        char* data = (char*) buffer->data();
-        data += offset;
-        while (size > 0) {
-            int numChars = fwrite(data, sizeof(char), 1024, pFile);
-            int numBytes = numChars * sizeof(char);
-            size -= numBytes;
-            data += numBytes;
-        }
-        fclose(pFile);
-    }
-    return;
-}
-
-extern int storeBitmapToFile(SkBitmap* bitmap, const char* filename) {
-    bitmap->lockPixels();
-    uint8_t* data = (uint8_t *)bitmap->getPixels();
-    int size = bitmap->getSize();
-    FILE* fp = fopen(filename, "w+");
-
-    if (NULL == fp) {
-        printf("Cannot open the output file! \n");
-        return -1;
-    } else {
-        while (size > 0) {
-            int numChars = fwrite(data, sizeof(char), 1024, fp);
-            int numBytes = numChars * sizeof(char);
-            size -= numBytes;
-            data += numBytes;
-        }
-        fclose(fp);
-    }
-    return 0;
-}
-
-static int64_t getNowUs() {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-
-    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
-}
-
-OmxJpegImageDecoder::OmxJpegImageDecoder() {
-    status_t err = mClient.connect();
-    CHECK_EQ(err, (status_t)OK);
-}
-
-OmxJpegImageDecoder::~OmxJpegImageDecoder() {
-    mClient.disconnect();
-}
-
-bool OmxJpegImageDecoder::onDecode(SkStream* stream,
-        SkBitmap* bm, Mode mode) {
-    sp<MediaSource> source = prepareMediaSource(stream);
-    sp<MetaData> meta = source->getFormat();
-    int width;
-    int height;
-    meta->findInt32(kKeyWidth, &width);
-    meta->findInt32(kKeyHeight, &height);
-    configBitmapSize(
-            bm, getPrefColorType(k32Bit_SrcDepth, false),
-            width, height);
-
-    // mode == DecodeBounds
-    if (mode == SkImageDecoder::kDecodeBounds_Mode) {
-        return true;
-    }
-
-    // mode == DecodePixels
-    if (!this->allocPixelRef(bm, NULL)) {
-        ALOGI("Cannot allocPixelRef()!");
-        return false;
-    }
-
-    sp<MediaSource> decoder = getDecoder(&mClient, source);
-    return decodeSource(decoder, source, bm);
-}
-
-JPEGSource* OmxJpegImageDecoder::prepareMediaSource(SkStream* stream) {
-    DataSource::RegisterDefaultSniffers();
-    sp<DataSource> dataSource = new StreamSource(stream);
-    return new JPEGSource(dataSource);
-}
-
-sp<MediaSource> OmxJpegImageDecoder::getDecoder(
-        OMXClient *client, const sp<MediaSource>& source) {
-    sp<MetaData> meta = source->getFormat();
-    sp<MediaSource> decoder = OMXCodec::Create(
-            client->interface(), meta, false /* createEncoder */, source);
-
-    CHECK(decoder != NULL);
-    return decoder;
-}
-
-bool OmxJpegImageDecoder::decodeSource(sp<MediaSource> decoder,
-        const sp<MediaSource>& source, SkBitmap* bm) {
-    status_t rt = decoder->start();
-    if (rt != OK) {
-        ALOGE("Cannot start OMX Decoder!");
-        return false;
-    }
-    int64_t startTime = getNowUs();
-    MediaBuffer *buffer;
-
-    // decode source
-    status_t err = decoder->read(&buffer, NULL);
-    int64_t duration = getNowUs() - startTime;
-
-    if (err != OK) {
-        CHECK(buffer == NULL);
-    }
-    printf("Duration in decoder->read(): %.1f (msecs). \n",
-                duration / 1E3 );
-
-    // Copy pixels from buffer to bm.
-    // May need to check buffer->rawBytes() == bm->rawBytes().
-    CHECK_EQ(buffer->size(), bm->getSize());
-    memcpy(bm->getPixels(), buffer->data(), buffer->size());
-    buffer->release();
-    decoder->stop();
-
-    return true;
-}
-
-void OmxJpegImageDecoder::configBitmapSize(SkBitmap* bm, SkColorType pref,
-        int width, int height) {
-    // Set the color space to ARGB_8888 for now (ignoring pref)
-    // because of limitation in hardware support.
-    bm->setInfo(SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType));
-}
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
deleted file mode 100644
index e487245..0000000
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef OMXJPEGIMAGEDECODER
-#define OMXJPEGIMAGEDECODER
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <media/stagefright/JPEGSource.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <SkImageDecoder.h>
-#include <SkStream.h>
-
-using namespace android;
-
-extern int storeBitmapToFile(SkBitmap* bitmap, const char* filename);
-
-class OmxJpegImageDecoder : public SkImageDecoder {
-public:
-    OmxJpegImageDecoder();
-    ~OmxJpegImageDecoder();
-
-    virtual Format getFormat() const {
-        return kJPEG_Format;
-    }
-
-protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
-
-private:
-    JPEGSource* prepareMediaSource(SkStream* stream);
-    sp<MediaSource> getDecoder(OMXClient* client, const sp<MediaSource>& source);
-    bool decodeSource(sp<MediaSource> decoder, const sp<MediaSource>& source,
-            SkBitmap* bm);
-    void configBitmapSize(SkBitmap* bm, SkColorType, int width, int height);
-
-    OMXClient mClient;
-};
-
-#endif
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index efba03d..16c6075 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -21,6 +21,7 @@
     <integer name="def_screen_off_timeout">60000</integer>
     <integer name="def_sleep_timeout">-1</integer>
     <bool name="def_airplane_mode_on">false</bool>
+    <bool name="def_theater_mode_on">false</bool>
     <!-- Comma-separated list of bluetooth, wifi, and cell. -->
     <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string>
     <string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 8c51caf..e56806a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -71,7 +71,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 114;
+    private static final int DATABASE_VERSION = 116;
 
     private Context mContext;
     private int mUserHandle;
@@ -1828,20 +1828,43 @@
             upgradeVersion = 113;
         }
 
-        if (upgradeVersion < 114) {
-            db.beginTransaction();
-            SQLiteStatement stmt = null;
-            try {
-                stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
-                        + " VALUES(?,?);");
-                loadSetting(stmt, Settings.Global.VOLTE_VT_ENABLED, ImsConfig.FeatureValueConstants.ON);
-                db.setTransactionSuccessful();
-            } finally {
-                db.endTransaction();
-                if (stmt != null) stmt.close();
+        // We skipped 114 to handle a merge conflict with the introduction of theater mode.
+
+        if (upgradeVersion < 115) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                SQLiteStatement stmt = null;
+                try {
+                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+                            + " VALUES(?,?);");
+                    loadBooleanSetting(stmt, Global.THEATER_MODE_ON,
+                            R.bool.def_theater_mode_on);
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                    if (stmt != null) stmt.close();
+                }
             }
-            upgradeVersion = 114;
+            upgradeVersion = 115;
         }
+
+        if (upgradeVersion < 116) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                SQLiteStatement stmt = null;
+                try {
+                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+                            + " VALUES(?,?);");
+                    loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                    if (stmt != null) stmt.close();
+                }
+            }
+            upgradeVersion = 116;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -2438,6 +2461,9 @@
             loadBooleanSetting(stmt, Settings.Global.AIRPLANE_MODE_ON,
                     R.bool.def_airplane_mode_on);
 
+            loadBooleanSetting(stmt, Settings.Global.THEATER_MODE_ON,
+                    R.bool.def_theater_mode_on);
+
             loadStringSetting(stmt, Settings.Global.AIRPLANE_MODE_RADIOS,
                     R.string.def_airplane_mode_radios);
 
@@ -2584,7 +2610,7 @@
 
             loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
                     R.bool.def_guest_user_enabled);
-            loadSetting(stmt, Settings.Global.VOLTE_VT_ENABLED, ImsConfig.FeatureValueConstants.ON);
+            loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
             // --- New global settings start here
         } finally {
             if (stmt != null) stmt.close();
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7e6afa6..3c44245 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -92,6 +92,7 @@
     <uses-permission android:name="android.permission.FRAME_STATS" />
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
+    <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
 
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 8ef3791..f5df1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -144,7 +144,7 @@
             showSaverNotification();
             mShowing = SHOWING_SAVER;
         } else {
-            mNoMan.cancel(TAG_NOTIFICATION, ID_NOTIFICATION);
+            mNoMan.cancelAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, UserHandle.ALL);
             mShowing = SHOWING_NOTHING;
         }
     }
@@ -165,7 +165,7 @@
         if (n.headsUpContentView != null) {
             n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL);
     }
 
     private void showWarningNotification() {
@@ -202,7 +202,7 @@
         if (n.headsUpContentView != null) {
             n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL);
     }
 
     private void showSaverNotification() {
@@ -219,7 +219,7 @@
         if (hasSaverSettings()) {
             nb.setContentIntent(pendingActivity(mOpenSaverSettings));
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.ALL);
     }
 
     private void addStopSaverAction(Notification.Builder nb) {
@@ -340,6 +340,11 @@
         updateNotification();
     }
 
+    @Override
+    public void userSwitched() {
+        updateNotification();
+    }
+
     private void showStartSaverConfirmation() {
         if (mSaverConfirmation != null) return;
         final SystemUIDialog d = new SystemUIDialog(mContext);
@@ -369,7 +374,7 @@
             filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
             filter.addAction(ACTION_START_SAVER);
             filter.addAction(ACTION_STOP_SAVER);
-            mContext.registerReceiver(this, filter, null, mHandler);
+            mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, mHandler);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index d3c7dee..9459740 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -137,6 +137,7 @@
             filter.addAction(Intent.ACTION_BATTERY_CHANGED);
             filter.addAction(Intent.ACTION_SCREEN_OFF);
             filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(Intent.ACTION_USER_SWITCHED);
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
             mContext.registerReceiver(this, filter, null, mHandler);
@@ -207,6 +208,8 @@
                 mScreenOffTime = SystemClock.elapsedRealtime();
             } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                 mScreenOffTime = -1;
+            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                mWarnings.userSwitched();
             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
                 updateSaverMode();
             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) {
@@ -256,6 +259,7 @@
         void updateLowBatteryWarning();
         boolean isInvalidChargerWarningShowing();
         void dump(PrintWriter pw);
+        void userSwitched();
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index eb808c2..5c7909a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -571,6 +571,9 @@
                 cancel();
             } else {
                 dismiss();
+                if (ActivityManager.isUserAMonkey()) {
+                    return;
+                }
                 UserInfo user = mUserManager.createSecondaryUser(
                         mContext.getString(R.string.user_new_user_name), 0 /* flags */);
                 if (user == null) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 9c81f0a..1ed61fd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -3342,9 +3342,9 @@
         final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
 
         if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
-            addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
+            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
         } else {
-            clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
+            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
         }
 
         // Non-floating windows on high end devices must put up decor beneath the system bars and
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 6b9d95d..e184577 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -503,6 +503,14 @@
     // What we do when the user double-taps on home
     private int mDoubleTapOnHomeBehavior;
 
+    // Allowed theater mode wake actions
+    private boolean mAllowTheaterModeWakeFromKey;
+    private boolean mAllowTheaterModeWakeFromPowerKey;
+    private boolean mAllowTheaterModeWakeFromMotion;
+    private boolean mAllowTheaterModeWakeFromCameraLens;
+    private boolean mAllowTheaterModeWakeFromLidSwitch;
+    private boolean mAllowTheaterModeWakeFromWakeGesture;
+
     // Screenshot trigger states
     // Time to volume and power must be pressed within this interval of each other.
     private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;
@@ -656,7 +664,7 @@
             synchronized (mLock) {
                 if (shouldEnableWakeGestureLp()) {
                     performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-                    mPowerManager.wakeUp(SystemClock.uptimeMillis());
+                    wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture);
                 }
             }
         }
@@ -1022,6 +1030,21 @@
                 com.android.internal.R.bool.config_lidControlsSleep);
         mTranslucentDecorEnabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_enableTranslucentDecor);
+
+        mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromKey);
+        mAllowTheaterModeWakeFromPowerKey = mAllowTheaterModeWakeFromKey
+                || mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey);
+        mAllowTheaterModeWakeFromMotion = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion);
+        mAllowTheaterModeWakeFromCameraLens = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens);
+        mAllowTheaterModeWakeFromLidSwitch = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch);
+        mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture);
+
         readConfigurationDependentBehaviors();
 
         mAccessibilityManager = (AccessibilityManager) context.getSystemService(
@@ -3181,10 +3204,15 @@
             // whether it is taking care of insetting its content.  If not,
             // we need to use the parent's content frame so that the entire
             // window is positioned within that content.  Otherwise we can use
-            // the display frame and let the attached window take care of
+            // the overscan frame and let the attached window take care of
             // positioning its content appropriately.
             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                cf.set(attached.getOverscanFrameLw());
+                // Set the content frame of the attached window to the parent's decor frame
+                // (same as content frame when IME isn't present) if specifically requested by
+                // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
+                // Otherwise, use the overscan frame.
+                cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
+                        ? attached.getContentFrameLw() : attached.getOverscanFrameLw());
             } else {
                 // If the window is resizing, then we want to base the content
                 // frame on our attached content frame to resize...  however,
@@ -4060,7 +4088,7 @@
         updateRotation(true);
 
         if (lidOpen) {
-            mPowerManager.wakeUp(SystemClock.uptimeMillis());
+            wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch);
         } else if (!mLidControlsSleep) {
             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
         }
@@ -4082,7 +4110,7 @@
             } else {
                 intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
             }
-            mPowerManager.wakeUp(whenNanos / 1000000);
+            wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens);
             mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
         }
         mCameraLensCoverState = lensCoverState;
@@ -4260,7 +4288,8 @@
         // key processing.
         if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
             if (isWakeKey) {
-                mPowerManager.wakeUp(event.getEventTime());
+                wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER
+                        ? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey);
             }
             return result;
         }
@@ -4509,8 +4538,10 @@
         }
 
         if (isWakeKey) {
-            mPowerManager.wakeUp(event.getEventTime());
+            wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER
+                    ? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey);
         }
+
         return result;
     }
 
@@ -4553,7 +4584,7 @@
     @Override
     public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
         if ((policyFlags & FLAG_WAKE) != 0) {
-            mPowerManager.wakeUp(whenNanos / 1000000);
+            wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion);
             return 0;
         }
         if (shouldDispatchInputWhenNonInteractive()) {
@@ -4731,6 +4762,14 @@
         }
     }
 
+    private void wakeUp(long wakeTime, boolean wakeInTheaterMode) {
+        if (!wakeInTheaterMode && isTheaterModeEnabled()) {
+            return;
+        }
+
+        mPowerManager.wakeUp(wakeTime);
+    }
+
     // Called on the PowerManager's Notifier thread.
     @Override
     public void wakingUp() {
@@ -5609,6 +5648,11 @@
         ringTone.play();
     }
 
+    private boolean isTheaterModeEnabled() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.THEATER_MODE_ON, 0) == 1;
+    }
+
     private boolean isGlobalAccessibilityGestureEnabled() {
         return Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index d05c280..41ce25d 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -65,11 +65,15 @@
 
     private boolean mUpdatesStopped;
 
+    private final boolean mAllowTheaterModeWakeFromDock;
+
     public DockObserver(Context context) {
         super(context);
 
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        mAllowTheaterModeWakeFromDock = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromDock);
 
         init();  // set initial status
 
@@ -126,8 +130,12 @@
         if (newState != mReportedDockState) {
             mReportedDockState = newState;
             if (mSystemReady) {
-                // Wake up immediately when docked or undocked.
-                mPowerManager.wakeUp(SystemClock.uptimeMillis());
+                // Wake up immediately when docked or undocked except in theater mode.
+                if (mAllowTheaterModeWakeFromDock
+                        || Settings.Global.getInt(getContext().getContentResolver(),
+                            Settings.Global.THEATER_MODE_ON, 0) == 0) {
+                    mPowerManager.wakeUp(SystemClock.uptimeMillis());
+                }
                 updateLocked();
             }
         }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c6d2db2..83d6986 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -137,11 +137,15 @@
         public void onReceive(Context context, Intent intent) {
             Slog.d(TAG, "Receieved: " + intent.getAction());
             if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
-                int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
-                if (DEBUG) {
-                    Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+                // If this is an outright uninstall rather than the first half of an
+                // app update sequence, cancel the jobs associated with the app.
+                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                    if (DEBUG) {
+                        Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+                    }
+                    cancelJobsForUid(uidRemoved);
                 }
-                cancelJobsForUid(uidRemoved);
             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 52807c0..5e95dfe 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -281,6 +281,9 @@
     // True if the device should wake up when plugged or unplugged.
     private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
 
+    // True if the device should wake up when plugged or unplugged in theater mode.
+    private boolean mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig;
+
     // True if the device should suspend when the screen is off due to proximity.
     private boolean mSuspendWhenScreenOffDueToProximityConfig;
 
@@ -420,6 +423,9 @@
     // True if the battery level is currently considered low.
     private boolean mBatteryLevelLow;
 
+    // True if theater mode is enabled
+    private boolean mTheaterModeEnabled;
+
     private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
             = new ArrayList<PowerManagerInternal.LowPowerModeListener>();
 
@@ -568,6 +574,9 @@
             resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
                     false, mSettingsObserver, UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.THEATER_MODE_ON),
+                    false, mSettingsObserver, UserHandle.USER_ALL);
             // Go.
             readConfigurationLocked();
             updateSettingsLocked();
@@ -585,6 +594,8 @@
                 com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
         mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_unplugTurnsOnScreen);
+        mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug);
         mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
         mDreamsSupportedConfig = resources.getBoolean(
@@ -636,6 +647,8 @@
                 UserHandle.USER_CURRENT);
         mStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver,
                 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_AC);
+        mTheaterModeEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.THEATER_MODE_ON, 0) == 1;
 
         final int oldScreenBrightnessSetting = mScreenBrightnessSetting;
         mScreenBrightnessSetting = Settings.System.getIntForUser(resolver,
@@ -1334,6 +1347,11 @@
             return false;
         }
 
+        // Don't wake while theater mode is enabled.
+        if (mTheaterModeEnabled && !mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig) {
+            return false;
+        }
+
         // Otherwise wake up!
         return true;
     }
@@ -2360,6 +2378,10 @@
                     + mDecoupleHalInteractiveModeFromDisplayConfig);
             pw.println("  mWakeUpWhenPluggedOrUnpluggedConfig="
                     + mWakeUpWhenPluggedOrUnpluggedConfig);
+            pw.println("  mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig="
+                    + mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig);
+            pw.println("  mTheaterModeEnabled="
+                    + mTheaterModeEnabled);
             pw.println("  mSuspendWhenScreenOffDueToProximityConfig="
                     + mSuspendWhenScreenOffDueToProximityConfig);
             pw.println("  mDreamsSupportedConfig=" + mDreamsSupportedConfig);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index f85e2d9..f19bfc2 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.util.Slog;
+import android.view.WindowManager;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
@@ -295,9 +296,10 @@
         }
     }
 
-    /** 
+    /**
      * Hide or show the on-screen Menu key. Only call this from the window manager, typically in
-     * response to a window with FLAG_NEEDS_MENU_KEY set.
+     * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
+     * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
      */
     @Override
     public void topAppWindowChanged(final boolean menuVisible) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index fefbe0a..f9b1704 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -120,8 +120,9 @@
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
             mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
             mReceiver.register(mContext);
-            maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_OWNER);
             refreshAgentList(UserHandle.USER_ALL);
+        } else if (phase == SystemService.PHASE_BOOT_COMPLETED && !isSafeMode()) {
+            maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_OWNER);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 30589b1..b0feca8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -376,10 +376,9 @@
             stack.dump(prefix + "  ", pw);
         }
         pw.println();
-        pw.println("  Application tokens in bottom up Z order:");
+        pw.println("  Application tokens in top down Z order:");
         int ndx = 0;
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9ceac41..a60be3b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -60,6 +60,12 @@
         return removed;
     }
 
+    void setSendingToBottom(boolean toBottom) {
+        for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) {
+            mAppTokens.get(appTokenNdx).sendingToBottom = toBottom;
+        }
+    }
+
     @Override
     public String toString() {
         return "{taskId=" + taskId + " appTokens=" + mAppTokens + "}";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0a0e8a1..57d793f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -619,6 +619,9 @@
 
     boolean mTurnOnScreen;
 
+    // Whether or not a layout can cause a wake up when theater mode is enabled.
+    boolean mAllowTheaterModeWakeFromLayout;
+
     DragState mDragState = null;
 
     // For frozen screen animations.
@@ -881,6 +884,9 @@
 
         mAnimator = new WindowAnimator(this);
 
+        mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
+
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
         initPolicy();
 
@@ -5052,6 +5058,10 @@
                     }
                 }
                 stack.moveTaskToTop(task);
+                if (mAppTransition.isTransitionSet()) {
+                    task.setSendingToBottom(false);
+                }
+                moveStackWindowsLocked(displayContent);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -5070,6 +5080,9 @@
                 }
                 final TaskStack stack = task.mStack;
                 stack.moveTaskToBottom(task);
+                if (mAppTransition.isTransitionSet()) {
+                    task.setSendingToBottom(true);
+                }
                 moveStackWindowsLocked(stack.getDisplayContent());
             }
         } finally {
@@ -9953,8 +9966,12 @@
         }
 
         if (mTurnOnScreen) {
-            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
-            mPowerManager.wakeUp(SystemClock.uptimeMillis());
+            if (mAllowTheaterModeWakeFromLayout
+                    || Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.THEATER_MODE_ON, 0) == 0) {
+                if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
+                mPowerManager.wakeUp(SystemClock.uptimeMillis());
+            }
             mTurnOnScreen = false;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b4a7f04..806f7c5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -704,9 +704,8 @@
         WindowState ws = this;
         WindowList windows = getWindowList();
         while (true) {
-            if ((ws.mAttrs.privateFlags
-                    & WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY) != 0) {
-                return (ws.mAttrs.flags & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
+            if (ws.mAttrs.needsMenuKey != WindowManager.LayoutParams.NEEDS_MENU_UNSET) {
+                return ws.mAttrs.needsMenuKey == WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
             }
             // If we reached the bottom of the range of windows we are considering,
             // assume no menu is needed.
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index f934963..354fa2e 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -484,10 +484,10 @@
 
     /**
      * Notifies this {@code Call} that an account has been selected and to proceed with placing
-     * an outgoing call.
+     * an outgoing call. Optionally sets this account as the default account.
      */
-    public void phoneAccountSelected(PhoneAccountHandle accountHandle) {
-        mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle);
+    public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
+        mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
 
     }
 
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 795053d..2932721 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -898,6 +898,13 @@
     }
 
     /**
+     * @hide
+     */
+    public final ConnectionService getConnectionService() {
+        return mConnectionService;
+    }
+
+    /**
      * Sets the conference that this connection is a part of. This will fail if the connection is
      * already part of a conference call. {@link #resetConference} to un-set the conference first.
      *
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index fd3cf2e..62b8dea 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -189,14 +189,16 @@
     }
 
     /**
-     * Instructs Telecom to add a PhoneAccountHandle to the specified call
+     * Instructs Telecom to add a PhoneAccountHandle to the specified call.
      *
-     * @param callId The identifier of the call
-     * @param accountHandle The PhoneAccountHandle through which to place the call
+     * @param callId The identifier of the call.
+     * @param accountHandle The PhoneAccountHandle through which to place the call.
+     * @param setDefault {@code True} if this account should be set as the default for calls.
      */
-    public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle) {
+    public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle,
+            boolean setDefault) {
         try {
-            mAdapter.phoneAccountSelected(callId, accountHandle);
+            mAdapter.phoneAccountSelected(callId, accountHandle, setDefault);
         } catch (RemoteException e) {
         }
     }
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 66b52ae..402df30 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -105,11 +105,17 @@
      */
     public static final String SCHEME_SIP = "sip";
 
+    /**
+     * Indicating no color is set.
+     */
+    public static final int NO_COLOR = -1;
+
     private final PhoneAccountHandle mAccountHandle;
     private final Uri mAddress;
     private final Uri mSubscriptionAddress;
     private final int mCapabilities;
     private final int mIconResId;
+    private final int mColor;
     private final CharSequence mLabel;
     private final CharSequence mShortDescription;
     private final List<String> mSupportedUriSchemes;
@@ -120,6 +126,7 @@
         private Uri mSubscriptionAddress;
         private int mCapabilities;
         private int mIconResId;
+        private int mColor = NO_COLOR;
         private CharSequence mLabel;
         private CharSequence mShortDescription;
         private List<String> mSupportedUriSchemes = new ArrayList<String>();
@@ -141,6 +148,7 @@
             mSubscriptionAddress = phoneAccount.getSubscriptionAddress();
             mCapabilities = phoneAccount.getCapabilities();
             mIconResId = phoneAccount.getIconResId();
+            mColor = phoneAccount.getColor();
             mLabel = phoneAccount.getLabel();
             mShortDescription = phoneAccount.getShortDescription();
             mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
@@ -166,6 +174,11 @@
             return this;
         }
 
+        public Builder setColor(int value) {
+            this.mColor = value;
+            return this;
+        }
+
         public Builder setShortDescription(CharSequence value) {
             this.mShortDescription = value;
             return this;
@@ -219,6 +232,7 @@
                     mSubscriptionAddress,
                     mCapabilities,
                     mIconResId,
+                    mColor,
                     mLabel,
                     mShortDescription,
                     mSupportedUriSchemes);
@@ -231,6 +245,7 @@
             Uri subscriptionAddress,
             int capabilities,
             int iconResId,
+            int color,
             CharSequence label,
             CharSequence shortDescription,
             List<String> supportedUriSchemes) {
@@ -239,6 +254,7 @@
         mSubscriptionAddress = subscriptionAddress;
         mCapabilities = capabilities;
         mIconResId = iconResId;
+        mColor = color;
         mLabel = label;
         mShortDescription = shortDescription;
         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
@@ -371,6 +387,15 @@
     }
 
     /**
+     * A highlight color to use in displaying information about this {@code PhoneAccount}.
+     *
+     * @return A hexadecimal color value.
+     */
+    public int getColor() {
+        return mColor;
+    }
+
+    /**
      * An icon to represent this {@code PhoneAccount} in a user interface.
      *
      * @return An icon for this {@code PhoneAccount}.
@@ -418,6 +443,7 @@
         out.writeParcelable(mSubscriptionAddress, 0);
         out.writeInt(mCapabilities);
         out.writeInt(mIconResId);
+        out.writeInt(mColor);
         out.writeCharSequence(mLabel);
         out.writeCharSequence(mShortDescription);
         out.writeList(mSupportedUriSchemes);
@@ -444,6 +470,7 @@
         mSubscriptionAddress = in.readParcelable(getClass().getClassLoader());
         mCapabilities = in.readInt();
         mIconResId = in.readInt();
+        mColor = in.readInt();
         mLabel = in.readCharSequence();
         mShortDescription = in.readCharSequence();
 
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 138a877..863fff2 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -46,7 +46,8 @@
 
     void postDialContinue(String callId, boolean proceed);
 
-    void phoneAccountSelected(String callId, in PhoneAccountHandle accountHandle);
+    void phoneAccountSelected(String callId, in PhoneAccountHandle accountHandle,
+            boolean setDefault);
 
     void conference(String callId, String otherCallId);
 
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java
index b9de871..f2df079 100644
--- a/telephony/java/android/telephony/SubInfoRecord.java
+++ b/telephony/java/android/telephony/SubInfoRecord.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.graphics.drawable.BitmapDrawable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -107,6 +108,31 @@
         this.mnc = mnc;
     }
 
+    /**
+     * Returns the string displayed to the user that identifies this subscription
+     */
+    public String getLabel() {
+        return this.displayName;
+    }
+
+    /**
+     * Return the icon used to identify this SIM.
+     * TODO: return the correct drawable.
+     */
+    public BitmapDrawable getIconDrawable() {
+        return new BitmapDrawable();
+    }
+
+    /**
+     * Return the color to be used for when displaying to the user. This is the value of the color.
+     * ex: 0x00ff00
+     */
+    public int getColor() {
+        // Note: This color is currently an index into a list of drawables, but this is soon to
+        // change.
+        return this.color;
+    }
+
     public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() {
         @Override
         public SubInfoRecord createFromParcel(Parcel source) {
diff --git a/telephony/java/com/android/internal/telephony/DcParamObject.java b/telephony/java/com/android/internal/telephony/DcParamObject.java
index 2736e6f..c92988f 100644
--- a/telephony/java/com/android/internal/telephony/DcParamObject.java
+++ b/telephony/java/com/android/internal/telephony/DcParamObject.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 MediaTek Inc.
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index defb43b..a4e9486 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -99,6 +99,7 @@
     public static final int EVENT_PROVISIONING_APN_ALARM = BASE + 39;
     public static final int CMD_NET_STAT_POLL = BASE + 40;
     public static final int EVENT_DATA_RAT_CHANGED = BASE + 41;
+    public static final int CMD_CLEAR_PROVISIONING_SPINNER = BASE + 42;
 
     /***** Constants *****/
 
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 117fc24..b7f64f6 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1141,9 +1141,10 @@
 ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir,
                                     const AaptGroupEntry& kind,
                                     const String8& resType,
-                                    sp<FilePathStore>& fullResPaths)
+                                    sp<FilePathStore>& fullResPaths,
+                                    const bool overwrite)
 {
-    ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths);
+    ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths, overwrite);
     if (res > 0) {
         mGroupEntries.add(kind);
     }
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index d809c5b..7ae5368 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -591,7 +591,8 @@
                                   const String8& srcDir,
                                   const AaptGroupEntry& kind,
                                   const String8& resType,
-                                  sp<FilePathStore>& fullResPaths);
+                                  sp<FilePathStore>& fullResPaths,
+                                  const bool overwrite=false);
 
     ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir);
     ssize_t slurpResourceZip(Bundle* bundle, const char* filename);
diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h
index 779c423..4f999a2 100644
--- a/tools/aapt/ConfigDescription.h
+++ b/tools/aapt/ConfigDescription.h
@@ -28,10 +28,12 @@
         memset(this, 0, sizeof(*this));
         size = sizeof(android::ResTable_config);
     }
+
     ConfigDescription(const android::ResTable_config&o) {
         *static_cast<android::ResTable_config*>(this) = o;
         size = sizeof(android::ResTable_config);
     }
+
     ConfigDescription(const ConfigDescription&o) {
         *static_cast<android::ResTable_config*>(this) = o;
     }
@@ -41,6 +43,7 @@
         size = sizeof(android::ResTable_config);
         return *this;
     }
+
     ConfigDescription& operator=(const ConfigDescription& o) {
         *static_cast<android::ResTable_config*>(this) = o;
         return *this;
diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp
index d60a07f..8835fb0 100644
--- a/tools/aapt/ResourceIdCache.cpp
+++ b/tools/aapt/ResourceIdCache.cpp
@@ -9,8 +9,6 @@
 #include <utils/Log.h>
 #include "ResourceIdCache.h"
 #include <map>
-using namespace std;
-
 
 static size_t mHits = 0;
 static size_t mMisses = 0;
@@ -29,7 +27,7 @@
     CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { }
 };
 
-static map< uint32_t, CacheEntry > mIdMap;
+static std::map< uint32_t, CacheEntry > mIdMap;
 
 
 // djb2; reasonable choice for strings when collisions aren't particularly important
@@ -63,7 +61,7 @@
         bool onlyPublic) {
     const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
     const uint32_t hashcode = hash(hashedName);
-    map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
+    std::map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
     if (item == mIdMap.end()) {
         // cache miss
         mMisses++;
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index bef5181..4993262 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -213,6 +213,10 @@
         return null;
     }
 
+    @Nullable
+    /*package*/ static String getFontLocation() {
+        return sFontLocation;
+    }
 
     // ---- native methods ----
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Accessor.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Accessor.java
deleted file mode 100644
index adad2ac..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Accessor.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-package android.graphics;
-
-/**
- * Class allowing access to package-protected methods/fields.
- */
-public class Typeface_Accessor {
-
-    public static void resetDefaults() {
-        Typeface.sDefaults = null;
-    }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 276e134..b9460b4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -27,6 +27,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.graphics.FontFamily_Delegate.getFontLocation;
+
 /**
  * Delegate implementing the native methods of android.graphics.Typeface
  *
@@ -48,8 +50,6 @@
     private static final DelegateManager<Typeface_Delegate> sManager =
             new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class);
 
-    // ---- delegate helper data ----
-    private static String sFontLocation;
 
     // ---- delegate data ----
 
@@ -61,11 +61,8 @@
 
     private static long sDefaultTypeface;
 
+
     // ---- Public Helper methods ----
-    public static synchronized void setFontLocation(String fontLocation) {
-        sFontLocation = fontLocation;
-        FontFamily_Delegate.setFontLocation(fontLocation);
-    }
 
     public static Typeface_Delegate getDelegate(long nativeTypeface) {
         return sManager.getDelegate(nativeTypeface);
@@ -131,6 +128,18 @@
         return fonts;
     }
 
+    /**
+     * Clear the default typefaces when disposing bridge.
+     */
+    public static void resetDefaults() {
+        // Sometimes this is called before the Bridge is initialized. In that case, we don't want to
+        // initialize Typeface because the SDK fonts location hasn't been set.
+        if (FontFamily_Delegate.getFontLocation() != null) {
+            Typeface.sDefaults = null;
+        }
+    }
+
+
     // ---- native methods ----
 
     @LayoutlibDelegate
@@ -193,7 +202,7 @@
 
     @LayoutlibDelegate
     /*package*/ static File getSystemFontConfigLocation() {
-        return new File(sFontLocation);
+        return new File(getFontLocation());
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 3d0e1e8..825731b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -38,7 +38,7 @@
 
 import android.content.res.BridgeAssetManager;
 import android.graphics.Bitmap;
-import android.graphics.Typeface_Accessor;
+import android.graphics.FontFamily_Delegate;
 import android.graphics.Typeface_Delegate;
 import android.os.Looper;
 import android.os.Looper_Accessor;
@@ -250,7 +250,7 @@
         }
 
         // load the fonts.
-        Typeface_Delegate.setFontLocation(fontLocation.getAbsolutePath());
+        FontFamily_Delegate.setFontLocation(fontLocation.getAbsolutePath());
 
         // now parse com.android.internal.R (and only this one as android.R is a subset of
         // the internal version), and put the content in the maps.
@@ -303,7 +303,7 @@
         BridgeAssetManager.clearSystem();
 
         // dispose of the default typeface.
-        Typeface_Accessor.resetDefaults();
+        Typeface_Delegate.resetDefaults();
 
         return true;
     }
diff --git a/tools/split-select/Abi.cpp b/tools/split-select/Abi.cpp
new file mode 100644
index 0000000..20654b6
--- /dev/null
+++ b/tools/split-select/Abi.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "Abi.h"
+
+namespace split {
+namespace abi {
+
+static const std::vector<Variant> sNoneVariants = {};
+static const std::vector<Variant> sArmVariants =
+        {Variant::armeabi, Variant::armeabi_v7a, Variant::arm64_v8a};
+static const std::vector<Variant> sIntelVariants = {Variant::x86, Variant::x86_64};
+static const std::vector<Variant> sMipsVariants = {Variant::mips, Variant::mips64};
+
+Family getFamily(Variant variant) {
+    switch (variant) {
+        case Variant::none:
+            return Family::none;
+        case Variant::armeabi:
+        case Variant::armeabi_v7a:
+        case Variant::arm64_v8a:
+            return Family::arm;
+        case Variant::x86:
+        case Variant::x86_64:
+            return Family::intel;
+        case Variant::mips:
+        case Variant::mips64:
+            return Family::mips;
+    }
+    return Family::none;
+}
+
+const std::vector<Variant>& getVariants(Family family) {
+    switch (family) {
+        case Family::none:
+            return sNoneVariants;
+        case Family::arm:
+            return sArmVariants;
+        case Family::intel:
+            return sIntelVariants;
+        case Family::mips:
+            return sMipsVariants;
+    }
+    return sNoneVariants;
+}
+
+const char* toString(Variant variant) {
+    switch (variant) {
+        case Variant::none:
+            return "";
+        case Variant::armeabi:
+            return "armeabi";
+        case Variant::armeabi_v7a:
+            return "armeabi-v7a";
+        case Variant::arm64_v8a:
+            return "arm64-v8a";
+        case Variant::x86:
+            return "x86";
+        case Variant::x86_64:
+            return "x86_64";
+        case Variant::mips:
+            return "mips";
+        case Variant::mips64:
+            return "mips64";
+    }
+    return "";
+}
+
+} // namespace abi
+} // namespace split
diff --git a/tools/split-select/Abi.h b/tools/split-select/Abi.h
new file mode 100644
index 0000000..3e00eba
--- /dev/null
+++ b/tools/split-select/Abi.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef H_ANDROID_SPLIT_ABI
+#define H_ANDROID_SPLIT_ABI
+
+#include <vector>
+
+namespace split {
+namespace abi {
+
+enum class Variant {
+    none = 0,
+    armeabi,
+    armeabi_v7a,
+    arm64_v8a,
+    x86,
+    x86_64,
+    mips,
+    mips64,
+};
+
+enum class Family {
+    none,
+    arm,
+    intel,
+    mips,
+};
+
+Family getFamily(Variant variant);
+const std::vector<Variant>& getVariants(Family family);
+const char* toString(Variant variant);
+
+} // namespace abi
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_ABI
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
new file mode 100644
index 0000000..d0b7287
--- /dev/null
+++ b/tools/split-select/Android.mk
@@ -0,0 +1,119 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# 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.
+#
+
+# This tool is prebuilt if we're doing an app-only build.
+ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
+
+# TODO(adamlesinski): Enable OS X builds when I figure out how
+# to build with clang and libc++
+ifneq ($(HOST_OS),darwin)
+
+# ==========================================================
+# Setup some common variables for the different build
+# targets here.
+# ==========================================================
+LOCAL_PATH:= $(call my-dir)
+
+main := Main.cpp
+sources := \
+    Abi.cpp \
+    Grouper.cpp \
+    Rule.cpp \
+    RuleGenerator.cpp \
+    SplitDescription.cpp
+
+testSources := \
+    Grouper_test.cpp \
+    Rule_test.cpp \
+    RuleGenerator_test.cpp
+
+cIncludes := \
+    external/zlib \
+    frameworks/base/tools
+
+hostLdLibs :=
+hostStaticLibs := \
+    libaapt \
+    libandroidfw \
+    libpng \
+    liblog \
+    libutils \
+    libcutils \
+    libexpat \
+    libziparchive-host
+
+cFlags := -std=c++11 -Wall -Werror
+
+ifeq ($(HOST_OS),linux)
+    hostLdLibs += -lrt -ldl -lpthread
+endif
+
+# Statically link libz for MinGW (Win SDK under Linux),
+# and dynamically link for all others.
+ifneq ($(strip $(USE_MINGW)),)
+    hostStaticLibs += libz
+else
+    hostLdLibs += -lz
+endif
+
+
+# ==========================================================
+# Build the host static library: libsplit-select
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsplit-select
+
+LOCAL_SRC_FILES := $(sources)
+
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_CFLAGS += $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# ==========================================================
+# Build the host tests: libsplit-select_tests
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsplit-select_tests
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(testSources)
+
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
+LOCAL_LDLIBS += $(hostLdLibs)
+LOCAL_CFLAGS += $(cFlags)
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+# ==========================================================
+# Build the host executable: split-select
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := split-select
+
+LOCAL_SRC_FILES := $(main)
+
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
+LOCAL_LDLIBS += $(hostLdLibs)
+LOCAL_CFLAGS += $(cFlags)
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # Not OS X
+endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/split-select/Grouper.cpp b/tools/split-select/Grouper.cpp
new file mode 100644
index 0000000..15edf89
--- /dev/null
+++ b/tools/split-select/Grouper.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "Grouper.h"
+
+#include "SplitDescription.h"
+
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace split {
+
+template <typename Key, typename Value>
+static void addToVector(KeyedVector<Key, SortedVector<Value> >& group,
+        const Key& key, const Value& value) {
+    ssize_t idx = group.indexOfKey(key);
+    if (idx < 0) {
+        idx = group.add(key, SortedVector<Value>());
+    }
+    group.editValueAt(idx).add(value);
+}
+
+Vector<SortedVector<SplitDescription> >
+groupByMutualExclusivity(const Vector<SplitDescription>& splits) {
+    Vector<SortedVector<SplitDescription> > groups;
+
+    // Find mutually exclusive splits and group them.
+    KeyedVector<SplitDescription, SortedVector<SplitDescription> > densityGroups;
+    KeyedVector<SplitDescription, SortedVector<SplitDescription> > abiGroups;
+    KeyedVector<SplitDescription, SortedVector<SplitDescription> > localeGroups;
+    for (const SplitDescription& split : splits) {
+        if (split.config.density != 0) {
+            SplitDescription key(split);
+            key.config.density = 0;
+            key.config.sdkVersion = 0; // Ignore density so we can support anydpi.
+            addToVector(densityGroups, key, split);
+        } else if (split.abi != abi::Variant::none) {
+            SplitDescription key(split);
+            key.abi = abi::Variant::none;
+            addToVector(abiGroups, key, split);
+        } else if (split.config.locale != 0) {
+            SplitDescription key(split);
+            key.config.clearLocale();
+            addToVector(localeGroups, key, split);
+        } else {
+            groups.add();
+            groups.editTop().add(split);
+        }
+    }
+
+    const size_t densityCount = densityGroups.size();
+    for (size_t i = 0; i < densityCount; i++) {
+        groups.add(densityGroups[i]);
+    }
+
+    const size_t abiCount = abiGroups.size();
+    for (size_t i = 0; i < abiCount; i++) {
+        groups.add(abiGroups[i]);
+    }
+
+    const size_t localeCount = localeGroups.size();
+    for (size_t i = 0; i < localeCount; i++) {
+        groups.add(localeGroups[i]);
+    }
+    return groups;
+}
+
+} // namespace split
diff --git a/tools/split-select/Grouper.h b/tools/split-select/Grouper.h
new file mode 100644
index 0000000..5cb0b5b
--- /dev/null
+++ b/tools/split-select/Grouper.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef H_ANDROID_SPLIT_GROUPER
+#define H_ANDROID_SPLIT_GROUPER
+
+#include "SplitDescription.h"
+
+#include <utils/SortedVector.h>
+#include <utils/Vector.h>
+
+namespace split {
+
+android::Vector<android::SortedVector<SplitDescription> >
+groupByMutualExclusivity(const android::Vector<SplitDescription>& splits);
+
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_GROUPER
diff --git a/tools/split-select/Grouper_test.cpp b/tools/split-select/Grouper_test.cpp
new file mode 100644
index 0000000..4d146cd
--- /dev/null
+++ b/tools/split-select/Grouper_test.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "Grouper.h"
+
+#include "SplitDescription.h"
+
+#include <gtest/gtest.h>
+#include <initializer_list>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace split {
+
+class GrouperTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        Vector<SplitDescription> splits;
+        addSplit(splits, "en-rUS-sw600dp-hdpi");
+        addSplit(splits, "fr-rFR-sw600dp-hdpi");
+        addSplit(splits, "fr-rFR-sw600dp-xhdpi");
+        addSplit(splits, ":armeabi");
+        addSplit(splits, "en-rUS-sw300dp-xhdpi");
+        addSplit(splits, "large");
+        addSplit(splits, "pl-rPL");
+        addSplit(splits, "xlarge");
+        addSplit(splits, "en-rUS-sw600dp-xhdpi");
+        addSplit(splits, "en-rUS-sw300dp-hdpi");
+        addSplit(splits, "xxhdpi");
+        addSplit(splits, "hdpi");
+        addSplit(splits, "de-rDE");
+        addSplit(splits, "xhdpi");
+        addSplit(splits, ":x86");
+        addSplit(splits, "anydpi");
+        addSplit(splits, "v7");
+        addSplit(splits, "v8");
+        addSplit(splits, "sw600dp");
+        addSplit(splits, "sw300dp");
+        mGroups = groupByMutualExclusivity(splits);
+    }
+
+    void addSplit(Vector<SplitDescription>& splits, const char* str);
+    void expectHasGroupWithSplits(std::initializer_list<const char*> l);
+
+    Vector<SortedVector<SplitDescription> > mGroups;
+};
+
+TEST_F(GrouperTest, shouldHaveCorrectNumberOfGroups) {
+    EXPECT_EQ(12u, mGroups.size());
+}
+
+TEST_F(GrouperTest, shouldGroupDensities) {
+    expectHasGroupWithSplits({"en-rUS-sw300dp-hdpi", "en-rUS-sw300dp-xhdpi"});
+    expectHasGroupWithSplits({"en-rUS-sw600dp-hdpi", "en-rUS-sw600dp-xhdpi"});
+    expectHasGroupWithSplits({"fr-rFR-sw600dp-hdpi", "fr-rFR-sw600dp-xhdpi"});
+    expectHasGroupWithSplits({"hdpi", "xhdpi", "xxhdpi", "anydpi"});
+}
+
+TEST_F(GrouperTest, shouldGroupAbi) {
+    expectHasGroupWithSplits({":armeabi", ":x86"});
+}
+
+TEST_F(GrouperTest, shouldGroupLocale) {
+    expectHasGroupWithSplits({"pl-rPL", "de-rDE"});
+}
+
+TEST_F(GrouperTest, shouldGroupEachSplitIntoItsOwnGroup) {
+    expectHasGroupWithSplits({"large"});
+    expectHasGroupWithSplits({"xlarge"});
+    expectHasGroupWithSplits({"v7"});
+    expectHasGroupWithSplits({"v8"});
+    expectHasGroupWithSplits({"sw600dp"});
+    expectHasGroupWithSplits({"sw300dp"});
+}
+
+//
+// Helper methods
+//
+
+void GrouperTest::expectHasGroupWithSplits(std::initializer_list<const char*> l) {
+    Vector<SplitDescription> splits;
+    for (const char* str : l) {
+        splits.add();
+        if (!SplitDescription::parse(String8(str), &splits.editTop())) {
+            ADD_FAILURE() << "Failed to parse SplitDescription " << str;
+            return;
+        }
+    }
+    const size_t splitCount = splits.size();
+
+    const size_t groupCount = mGroups.size();
+    for (size_t i = 0; i < groupCount; i++) {
+        const SortedVector<SplitDescription>& group = mGroups[i];
+        if (group.size() != splitCount) {
+            continue;
+        }
+
+        size_t found = 0;
+        for (size_t j = 0; j < splitCount; j++) {
+            if (group.indexOf(splits[j]) >= 0) {
+                found++;
+            }
+        }
+
+        if (found == splitCount) {
+            return;
+        }
+    }
+
+    String8 errorMessage("Failed to find expected group [");
+    for (size_t i = 0; i < splitCount; i++) {
+        if (i != 0) {
+            errorMessage.append(", ");
+        }
+        errorMessage.append(splits[i].toString());
+    }
+    errorMessage.append("].\nActual:\n");
+
+    for (size_t i = 0; i < groupCount; i++) {
+        errorMessage.appendFormat("Group %d:\n", int(i + 1));
+        const SortedVector<SplitDescription>& group = mGroups[i];
+        for (size_t j = 0; j < group.size(); j++) {
+            errorMessage.append("  ");
+            errorMessage.append(group[j].toString());
+            errorMessage.append("\n");
+        }
+    }
+    ADD_FAILURE() << errorMessage.string();
+}
+
+void GrouperTest::addSplit(Vector<SplitDescription>& splits, const char* str) {
+    splits.add();
+    EXPECT_TRUE(SplitDescription::parse(String8(str), &splits.editTop()));
+}
+
+} // namespace split
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
new file mode 100644
index 0000000..d6251c3
--- /dev/null
+++ b/tools/split-select/Main.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include <algorithm>
+#include <cstdio>
+
+#include "aapt/AaptUtil.h"
+
+#include "Grouper.h"
+#include "Rule.h"
+#include "RuleGenerator.h"
+#include "SplitDescription.h"
+
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace split {
+
+static void usage() {
+    fprintf(stderr,
+            "split-select --help\n"
+            "split-select --target <config> --split <path/to/apk> [--split <path/to/apk> [...]]\n"
+            "split-select --generate --split <path/to/apk> [--split <path/to/apk> [...]]\n"
+            "\n"
+            "  --help                   Displays more information about this program.\n"
+            "  --target <config>        Performs the Split APK selection on the given configuration.\n"
+            "  --generate               Generates the logic for selecting the Split APK, in JSON format.\n"
+            "  --split <path/to/apk>    Includes a Split APK in the selection process.\n"
+            "\n"
+            "  Where <config> is an extended AAPT resource qualifier of the form\n"
+            "  'resource-qualifiers:extended-qualifiers', where 'resource-qualifiers' is an AAPT resource\n"
+            "  qualifier (ex: en-rUS-sw600dp-xhdpi), and 'extended-qualifiers' is an ordered list of one\n"
+            "  qualifier (or none) from each category:\n"
+            "    Architecture: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips\n");
+}
+
+static void help() {
+    usage();
+    fprintf(stderr, "\n"
+            "  Generates the logic for selecting a Split APK given some target Android device configuration.\n"
+            "  Using the flag --generate will emit a JSON encoded tree of rules that must be satisfied in order\n"
+            "  to install the given Split APK. Using the flag --target along with the device configuration\n"
+            "  will emit the set of Split APKs to install, following the same logic that would have been emitted\n"
+            "  via JSON.\n");
+}
+
+class SplitSelector {
+public:
+    SplitSelector() = default;
+    SplitSelector(const Vector<SplitDescription>& splits);
+
+    Vector<SplitDescription> getBestSplits(const SplitDescription& target) const;
+
+    template <typename RuleGenerator>
+    KeyedVector<SplitDescription, sp<Rule> > getRules() const;
+
+private:
+    Vector<SortedVector<SplitDescription> > mGroups;
+};
+
+SplitSelector::SplitSelector(const Vector<SplitDescription>& splits)
+    : mGroups(groupByMutualExclusivity(splits)) {
+}
+
+static void selectBestFromGroup(const SortedVector<SplitDescription>& splits,
+        const SplitDescription& target, Vector<SplitDescription>& splitsOut) {
+    SplitDescription bestSplit;
+    bool isSet = false;
+    const size_t splitCount = splits.size();
+    for (size_t j = 0; j < splitCount; j++) {
+        const SplitDescription& thisSplit = splits[j];
+        if (!thisSplit.match(target)) {
+            continue;
+        }
+
+        if (!isSet || thisSplit.isBetterThan(bestSplit, target)) {
+            isSet = true;
+            bestSplit = thisSplit;
+        }
+    }
+
+    if (isSet) {
+        splitsOut.add(bestSplit);
+    }
+}
+
+Vector<SplitDescription> SplitSelector::getBestSplits(const SplitDescription& target) const {
+    Vector<SplitDescription> bestSplits;
+    const size_t groupCount = mGroups.size();
+    for (size_t i = 0; i < groupCount; i++) {
+        selectBestFromGroup(mGroups[i], target, bestSplits);
+    }
+    return bestSplits;
+}
+
+template <typename RuleGenerator>
+KeyedVector<SplitDescription, sp<Rule> > SplitSelector::getRules() const {
+    KeyedVector<SplitDescription, sp<Rule> > rules;
+
+    const size_t groupCount = mGroups.size();
+    for (size_t i = 0; i < groupCount; i++) {
+        const SortedVector<SplitDescription>& splits = mGroups[i];
+        const size_t splitCount = splits.size();
+        for (size_t j = 0; j < splitCount; j++) {
+            sp<Rule> rule = Rule::simplify(RuleGenerator::generate(splits, j));
+            if (rule != NULL) {
+                rules.add(splits[j], rule);
+            }
+        }
+    }
+    return rules;
+}
+
+Vector<SplitDescription> select(const SplitDescription& target, const Vector<SplitDescription>& splits) {
+    const SplitSelector selector(splits);
+    return selector.getBestSplits(target);
+}
+
+void generate(const KeyedVector<String8, Vector<SplitDescription> >& splits) {
+    Vector<SplitDescription> allSplits;
+    const size_t apkSplitCount = splits.size();
+    for (size_t i = 0; i < apkSplitCount; i++) {
+        allSplits.appendVector(splits[i]);
+    }
+    const SplitSelector selector(allSplits);
+    KeyedVector<SplitDescription, sp<Rule> > rules(selector.getRules<RuleGenerator>());
+
+    fprintf(stdout, "[\n");
+    for (size_t i = 0; i < apkSplitCount; i++) {
+        sp<Rule> masterRule = new Rule();
+        masterRule->op = Rule::OR_SUBRULES;
+        const Vector<SplitDescription>& splitDescriptions = splits[i];
+        const size_t splitDescriptionCount = splitDescriptions.size();
+        for (size_t j = 0; j < splitDescriptionCount; j++) {
+            masterRule->subrules.add(rules.valueFor(splitDescriptions[j]));
+        }
+        masterRule = Rule::simplify(masterRule);
+        fprintf(stdout, "  {\n    \"path\": \"%s\",\n    \"rules\": %s\n  }%s\n",
+                splits.keyAt(i).string(),
+                masterRule->toJson(2).string(),
+                i < apkSplitCount - 1 ? "," : "");
+    }
+    fprintf(stdout, "]\n");
+}
+
+static void removeRuntimeQualifiers(ConfigDescription* outConfig) {
+    outConfig->imsi = 0;
+    outConfig->orientation = ResTable_config::ORIENTATION_ANY;
+    outConfig->screenWidth = ResTable_config::SCREENWIDTH_ANY;
+    outConfig->screenHeight = ResTable_config::SCREENHEIGHT_ANY;
+    outConfig->uiMode &= ResTable_config::UI_MODE_NIGHT_ANY;
+}
+
+static Vector<SplitDescription> extractSplitDescriptionsFromApk(const String8& path) {
+    AssetManager assetManager;
+    Vector<SplitDescription> splits;
+    int32_t cookie = 0;
+    if (!assetManager.addAssetPath(path, &cookie)) {
+        return splits;
+    }
+
+    const ResTable& res = assetManager.getResources(false);
+    if (res.getError() == NO_ERROR) {
+        Vector<ResTable_config> configs;
+        res.getConfigurations(&configs);
+        const size_t configCount = configs.size();
+        for (size_t i = 0; i < configCount; i++) {
+            splits.add();
+            splits.editTop().config = configs[i];
+        }
+    }
+
+    AssetDir* dir = assetManager.openNonAssetDir(cookie, "lib");
+    if (dir != NULL) {
+        const size_t fileCount = dir->getFileCount();
+        for (size_t i = 0; i < fileCount; i++) {
+            splits.add();
+            Vector<String8> parts = AaptUtil::splitAndLowerCase(dir->getFileName(i), '-');
+            if (parseAbi(parts, 0, &splits.editTop()) < 0) {
+                fprintf(stderr, "Malformed library %s\n", dir->getFileName(i).string());
+                splits.pop();
+            }
+        }
+        delete dir;
+    }
+    return splits;
+}
+
+static int main(int argc, char** argv) {
+    // Skip over the first argument.
+    argc--;
+    argv++;
+
+    bool generateFlag = false;
+    String8 targetConfigStr;
+    Vector<String8> splitApkPaths;
+    while (argc > 0) {
+        const String8 arg(*argv);
+        if (arg == "--target") {
+            argc--;
+            argv++;
+            if (argc < 1) {
+                fprintf(stderr, "Missing parameter for --split.\n");
+                usage();
+                return 1;
+            }
+            targetConfigStr.setTo(*argv);
+        } else if (arg == "--split") {
+            argc--;
+            argv++;
+            if (argc < 1) {
+                fprintf(stderr, "Missing parameter for --split.\n");
+                usage();
+                return 1;
+            }
+            splitApkPaths.add(String8(*argv));
+        } else if (arg == "--generate") {
+            generateFlag = true;
+        } else if (arg == "--help") {
+            help();
+            return 0;
+        } else {
+            fprintf(stderr, "Unknown argument '%s'\n", arg.string());
+            usage();
+            return 1;
+        }
+        argc--;
+        argv++;
+    }
+
+    if (!generateFlag && targetConfigStr == "") {
+        usage();
+        return 1;
+    }
+
+    if (splitApkPaths.size() == 0) {
+        usage();
+        return 1;
+    }
+
+    SplitDescription targetSplit;
+    if (!generateFlag) {
+        if (!SplitDescription::parse(targetConfigStr, &targetSplit)) {
+            fprintf(stderr, "Invalid --target config: '%s'\n",
+                    targetConfigStr.string());
+            usage();
+            return 1;
+        }
+
+        // We don't want to match on things that will change at run-time
+        // (orientation, w/h, etc.).
+        removeRuntimeQualifiers(&targetSplit.config);
+    }
+
+    KeyedVector<String8, Vector<SplitDescription> > apkPathSplitMap;
+    KeyedVector<SplitDescription, String8> splitApkPathMap;
+    Vector<SplitDescription> splitConfigs;
+    const size_t splitCount = splitApkPaths.size();
+    for (size_t i = 0; i < splitCount; i++) {
+        Vector<SplitDescription> splits = extractSplitDescriptionsFromApk(splitApkPaths[i]);
+        if (splits.isEmpty()) {
+            fprintf(stderr, "Invalid --split path: '%s'. No splits found.\n",
+                    splitApkPaths[i].string());
+            usage();
+            return 1;
+        }
+        apkPathSplitMap.replaceValueFor(splitApkPaths[i], splits);
+        const size_t apkSplitDescriptionCount = splits.size();
+        for (size_t j = 0; j < apkSplitDescriptionCount; j++) {
+            splitApkPathMap.replaceValueFor(splits[j], splitApkPaths[i]);
+        }
+        splitConfigs.appendVector(splits);
+    }
+
+    if (!generateFlag) {
+        Vector<SplitDescription> matchingConfigs = select(targetSplit, splitConfigs);
+        const size_t matchingConfigCount = matchingConfigs.size();
+        SortedVector<String8> matchingSplitPaths;
+        for (size_t i = 0; i < matchingConfigCount; i++) {
+            matchingSplitPaths.add(splitApkPathMap.valueFor(matchingConfigs[i]));
+        }
+
+        const size_t matchingSplitApkPathCount = matchingSplitPaths.size();
+        for (size_t i = 0; i < matchingSplitApkPathCount; i++) {
+            fprintf(stderr, "%s\n", matchingSplitPaths[i].string());
+        }
+    } else {
+        generate(apkPathSplitMap);
+    }
+    return 0;
+}
+
+} // namespace split
+
+int main(int argc, char** argv) {
+    return split::main(argc, argv);
+}
diff --git a/tools/split-select/Rule.cpp b/tools/split-select/Rule.cpp
new file mode 100644
index 0000000..9559fe2
--- /dev/null
+++ b/tools/split-select/Rule.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "Rule.h"
+
+#include <utils/String8.h>
+
+using namespace android;
+
+namespace split {
+
+inline static void indentStr(String8& str, int indent) {
+    while (indent > 0) {
+        str.append("  ");
+        indent--;
+    }
+}
+
+String8 Rule::toJson(int indent) const {
+    String8 str;
+    indentStr(str, indent);
+    str.append("{\n");
+    indent++;
+    indentStr(str, indent);
+    str.append("\"op\": \"");
+    switch (op) {
+        case ALWAYS_TRUE:
+            str.append("ALWAYS_TRUE");
+            break;
+        case GREATER_THAN:
+            str.append("GREATER_THAN");
+            break;
+        case LESS_THAN:
+            str.append("LESS_THAN");
+            break;
+        case EQUALS:
+            str.append("EQUALS");
+            break;
+        case AND_SUBRULES:
+            str.append("AND_SUBRULES");
+            break;
+        case OR_SUBRULES:
+            str.append("OR_SUBRULES");
+            break;
+        case CONTAINS_ANY:
+            str.append("CONTAINS_ANY");
+            break;
+        default:
+            str.appendFormat("%d", op);
+            break;
+    }
+    str.append("\"");
+
+    if (negate) {
+        str.append(",\n");
+        indentStr(str, indent);
+        str.append("\"negate\": true");
+    }
+
+    bool includeKey = true;
+    switch (op) {
+        case AND_SUBRULES:
+        case OR_SUBRULES:
+            includeKey = false;
+            break;
+        default:
+            break;
+    }
+
+    if (includeKey) {
+        str.append(",\n");
+        indentStr(str, indent);
+        str.append("\"property\": \"");
+        switch (key) {
+            case NONE:
+                str.append("NONE");
+                break;
+            case SDK_VERSION:
+                str.append("SDK_VERSION");
+                break;
+            case SCREEN_DENSITY:
+                str.append("SCREEN_DENSITY");
+                break;
+            case NATIVE_PLATFORM:
+                str.append("NATIVE_PLATFORM");
+                break;
+            case LANGUAGE:
+                str.append("LANGUAGE");
+                break;
+            default:
+                str.appendFormat("%d", key);
+                break;
+        }
+        str.append("\"");
+    }
+
+    if (op == AND_SUBRULES || op == OR_SUBRULES) {
+        str.append(",\n");
+        indentStr(str, indent);
+        str.append("\"subrules\": [\n");
+        const size_t subruleCount = subrules.size();
+        for (size_t i = 0; i < subruleCount; i++) {
+            str.append(subrules[i]->toJson(indent + 1));
+            if (i != subruleCount - 1) {
+                str.append(",");
+            }
+            str.append("\n");
+        }
+        indentStr(str, indent);
+        str.append("]");
+    } else {
+        switch (key) {
+            case SDK_VERSION:
+            case SCREEN_DENSITY: {
+                str.append(",\n");
+                indentStr(str, indent);
+                str.append("\"args\": [");
+                const size_t argCount = longArgs.size();
+                for (size_t i = 0; i < argCount; i++) {
+                    if (i != 0) {
+                        str.append(", ");
+                    }
+                    str.appendFormat("%d", longArgs[i]);
+                }
+                str.append("]");
+                break;
+            }
+            case LANGUAGE:
+            case NATIVE_PLATFORM: {
+                str.append(",\n");
+                indentStr(str, indent);
+                str.append("\"args\": [");
+                const size_t argCount = stringArgs.size();
+                for (size_t i = 0; i < argCount; i++) {
+                    if (i != 0) {
+                        str.append(", ");
+                    }
+                    str.append(stringArgs[i]);
+                }
+                str.append("]");
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    str.append("\n");
+    indent--;
+    indentStr(str, indent);
+    str.append("}");
+    return str;
+}
+
+sp<Rule> Rule::simplify(sp<Rule> rule) {
+    if (rule->op != AND_SUBRULES && rule->op != OR_SUBRULES) {
+        return rule;
+    }
+
+    Vector<sp<Rule> > newSubrules;
+    newSubrules.setCapacity(rule->subrules.size());
+    const size_t subruleCount = rule->subrules.size();
+    for (size_t i = 0; i < subruleCount; i++) {
+        sp<Rule> simplifiedRule = simplify(rule->subrules.editItemAt(i));
+        if (simplifiedRule != NULL) {
+            if (simplifiedRule->op == rule->op) {
+                newSubrules.appendVector(simplifiedRule->subrules);
+            } else {
+                newSubrules.add(simplifiedRule);
+            }
+        }
+    }
+
+    const size_t newSubruleCount = newSubrules.size();
+    if (newSubruleCount == 0) {
+        return NULL;
+    } else if (subruleCount == 1) {
+        return newSubrules.editTop();
+    }
+    rule->subrules = newSubrules;
+    return rule;
+}
+
+} // namespace split
diff --git a/tools/split-select/Rule.h b/tools/split-select/Rule.h
new file mode 100644
index 0000000..8029931
--- /dev/null
+++ b/tools/split-select/Rule.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef H_ANDROID_SPLIT_RULE
+#define H_ANDROID_SPLIT_RULE
+
+#include "SplitDescription.h"
+
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace split {
+
+struct Rule : public virtual android::RefBase {
+    inline Rule();
+
+    enum Operator {
+        LESS_THAN = 1,
+        GREATER_THAN,
+        EQUALS,
+        CONTAINS_ANY,
+        CONTAINS_ALL,
+        IS_TRUE,
+        IS_FALSE,
+        AND_SUBRULES,
+        OR_SUBRULES,
+        ALWAYS_TRUE,
+    };
+
+    Operator op;
+
+    enum Key {
+        NONE = 0,
+        SDK_VERSION,
+        SCREEN_DENSITY,
+        LANGUAGE,
+        NATIVE_PLATFORM,
+        TOUCH_SCREEN,
+        SCREEN_SIZE,
+        SCREEN_LAYOUT,
+    };
+
+    Key key;
+    bool negate;
+
+    android::Vector<android::String8> stringArgs;
+    android::Vector<int> longArgs;
+    android::Vector<double> doubleArgs;
+    android::Vector<android::sp<Rule> > subrules;
+
+    android::String8 toJson(int indent=0) const;
+
+    static android::sp<Rule> simplify(android::sp<Rule> rule);
+};
+
+Rule::Rule()
+: op(ALWAYS_TRUE)
+, key(NONE)
+, negate(false) {}
+
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_RULE
diff --git a/tools/split-select/RuleGenerator.cpp b/tools/split-select/RuleGenerator.cpp
new file mode 100644
index 0000000..669ae78
--- /dev/null
+++ b/tools/split-select/RuleGenerator.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "RuleGenerator.h"
+
+#include <algorithm>
+#include <cmath>
+#include <vector>
+#include <androidfw/ResourceTypes.h>
+
+using namespace android;
+
+namespace split {
+
+// Calculate the point at which the density selection changes between l and h.
+static inline int findMid(int l, int h) {
+    double root = sqrt((h*h) + (8*l*h));
+    return (double(-h) + root) / 2.0;
+}
+
+sp<Rule> RuleGenerator::generateDensity(const Vector<int>& allDensities, size_t index) {
+    sp<Rule> densityRule = new Rule();
+    densityRule->op = Rule::AND_SUBRULES;
+
+    const bool anyDensity = allDensities[index] == ResTable_config::DENSITY_ANY;
+    sp<Rule> any = new Rule();
+    any->op = Rule::EQUALS;
+    any->key = Rule::SCREEN_DENSITY;
+    any->longArgs.add((int)ResTable_config::DENSITY_ANY);
+    any->negate = !anyDensity;
+    densityRule->subrules.add(any);
+
+    if (!anyDensity) {
+        if (index > 0) {
+            sp<Rule> gt = new Rule();
+            gt->op = Rule::GREATER_THAN;
+            gt->key = Rule::SCREEN_DENSITY;
+            gt->longArgs.add(findMid(allDensities[index - 1], allDensities[index]) - 1);
+            densityRule->subrules.add(gt);
+        }
+
+        if (index + 1 < allDensities.size() && allDensities[index + 1] != ResTable_config::DENSITY_ANY) {
+            sp<Rule> lt = new Rule();
+            lt->op = Rule::LESS_THAN;
+            lt->key = Rule::SCREEN_DENSITY;
+            lt->longArgs.add(findMid(allDensities[index], allDensities[index + 1]));
+            densityRule->subrules.add(lt);
+        }
+    }
+    return densityRule;
+}
+
+sp<Rule> RuleGenerator::generateAbi(const Vector<abi::Variant>& splitAbis, size_t index) {
+    const abi::Variant thisAbi = splitAbis[index];
+    const std::vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi));
+
+    std::vector<abi::Variant>::const_iterator start =
+            std::find(familyVariants.begin(), familyVariants.end(), thisAbi);
+
+    std::vector<abi::Variant>::const_iterator end = familyVariants.end();
+    if (index + 1 < splitAbis.size()) {
+        end = std::find(start, familyVariants.end(), splitAbis[index + 1]);
+    }
+
+    sp<Rule> abiRule = new Rule();
+    abiRule->op = Rule::CONTAINS_ANY;
+    abiRule->key = Rule::NATIVE_PLATFORM;
+    while (start != end) {
+        abiRule->stringArgs.add(String8(abi::toString(*start)));
+        ++start;
+    }
+    return abiRule;
+}
+
+sp<Rule> RuleGenerator::generate(const SortedVector<SplitDescription>& group, size_t index) {
+    sp<Rule> rootRule = new Rule();
+    rootRule->op = Rule::AND_SUBRULES;
+
+    if (group[index].config.locale != 0) {
+        sp<Rule> locale = new Rule();
+        locale->op = Rule::EQUALS;
+        locale->key = Rule::LANGUAGE;
+        char str[RESTABLE_MAX_LOCALE_LEN];
+        group[index].config.getBcp47Locale(str);
+        locale->stringArgs.add(String8(str));
+        rootRule->subrules.add(locale);
+    }
+
+    if (group[index].config.sdkVersion != 0) {
+        sp<Rule> sdk = new Rule();
+        sdk->op = Rule::GREATER_THAN;
+        sdk->key = Rule::SDK_VERSION;
+        sdk->longArgs.add(group[index].config.sdkVersion - 1);
+        rootRule->subrules.add(sdk);
+    }
+
+    if (group[index].config.density != 0) {
+        size_t densityIndex = 0;
+        Vector<int> allDensities;
+        allDensities.add(group[index].config.density);
+
+        const size_t groupSize = group.size();
+        for (size_t i = 0; i < groupSize; i++) {
+            if (group[i].config.density != group[index].config.density) {
+                // This group differs by density.
+                allDensities.clear();
+                for (size_t j = 0; j < groupSize; j++) {
+                    allDensities.add(group[j].config.density);
+                }
+                densityIndex = index;
+                break;
+            }
+        }
+        rootRule->subrules.add(generateDensity(allDensities, densityIndex));
+    }
+
+    if (group[index].abi != abi::Variant::none) {
+        size_t abiIndex = 0;
+        Vector<abi::Variant> allVariants;
+        allVariants.add(group[index].abi);
+
+        const size_t groupSize = group.size();
+        for (size_t i = 0; i < groupSize; i++) {
+            if (group[i].abi != group[index].abi) {
+                // This group differs by ABI.
+                allVariants.clear();
+                for (size_t j = 0; j < groupSize; j++) {
+                    allVariants.add(group[j].abi);
+                }
+                abiIndex = index;
+                break;
+            }
+        }
+        rootRule->subrules.add(generateAbi(allVariants, abiIndex));
+    }
+
+    return rootRule;
+}
+
+} // namespace split
diff --git a/tools/split-select/RuleGenerator.h b/tools/split-select/RuleGenerator.h
new file mode 100644
index 0000000..619acd9
--- /dev/null
+++ b/tools/split-select/RuleGenerator.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef H_ANDROID_SPLIT_RULE_GENERATOR
+#define H_ANDROID_SPLIT_RULE_GENERATOR
+
+#include "Abi.h"
+#include "Rule.h"
+#include "SplitDescription.h"
+
+#include <utils/SortedVector.h>
+#include <utils/Vector.h>
+
+namespace split {
+
+struct RuleGenerator {
+    // Generate rules for a Split given the group of mutually exclusive splits it belongs to
+    static android::sp<Rule> generate(const android::SortedVector<SplitDescription>& group, size_t index);
+
+    static android::sp<Rule> generateAbi(const android::Vector<abi::Variant>& allVariants, size_t index);
+    static android::sp<Rule> generateDensity(const android::Vector<int>& allDensities, size_t index);
+};
+
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_RULE_GENERATOR
diff --git a/tools/split-select/RuleGenerator_test.cpp b/tools/split-select/RuleGenerator_test.cpp
new file mode 100644
index 0000000..60baabe
--- /dev/null
+++ b/tools/split-select/RuleGenerator_test.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "RuleGenerator.h"
+
+#include <algorithm>
+#include <gtest/gtest.h>
+#include <utils/String8.h>
+
+using namespace android;
+
+namespace split {
+
+static void expectDensityRule(const Vector<int>& densities, int density, int greaterThan, int lessThan);
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant,
+        std::initializer_list<const char*> matches);
+
+TEST(RuleGeneratorTest, testAbiRules) {
+    Vector<abi::Variant> abis;
+    abis.add(abi::Variant::armeabi);
+    abis.add(abi::Variant::armeabi_v7a);
+    abis.add(abi::Variant::x86);
+    std::sort(abis.begin(), abis.end());
+
+    expectAbiRule(abis, abi::Variant::armeabi, {"armeabi"});
+    expectAbiRule(abis, abi::Variant::armeabi_v7a, {"armeabi-v7a", "arm64-v8a"});
+    expectAbiRule(abis, abi::Variant::x86, {"x86", "x86_64"});
+}
+
+TEST(RuleGeneratorTest, testDensityRules) {
+    Vector<int> densities;
+    densities.add(ConfigDescription::DENSITY_HIGH);
+    densities.add(ConfigDescription::DENSITY_XHIGH);
+    densities.add(ConfigDescription::DENSITY_XXHIGH);
+    densities.add(ConfigDescription::DENSITY_ANY);
+
+    ASSERT_LT(263, ConfigDescription::DENSITY_XHIGH);
+    ASSERT_GT(262, ConfigDescription::DENSITY_HIGH);
+    ASSERT_LT(363, ConfigDescription::DENSITY_XXHIGH);
+    ASSERT_GT(362, ConfigDescription::DENSITY_XHIGH);
+
+    expectDensityRule(densities, ConfigDescription::DENSITY_HIGH, 0, 263);
+    expectDensityRule(densities, ConfigDescription::DENSITY_XHIGH, 262, 363);
+    expectDensityRule(densities, ConfigDescription::DENSITY_XXHIGH, 362, 0);
+    expectDensityRule(densities, ConfigDescription::DENSITY_ANY, 0, 0);
+}
+
+//
+// Helper methods.
+//
+
+static void expectDensityRule(const Vector<int>& densities, int density, int greaterThan, int lessThan) {
+    const int* iter = std::find(densities.begin(), densities.end(), density);
+    if (densities.end() == iter) {
+        ADD_FAILURE() << density << "dpi was not in the density list.";
+        return;
+    }
+
+    sp<Rule> rule = RuleGenerator::generateDensity(densities, iter - densities.begin());
+    if (rule->op != Rule::AND_SUBRULES) {
+        ADD_FAILURE() << "Op in rule for " << density << "dpi is not Rule::AND_SUBRULES.";
+        return;
+    }
+
+    size_t index = 0;
+
+    bool isAnyDpi = density == ConfigDescription::DENSITY_ANY;
+
+    sp<Rule> anyDpiRule = rule->subrules[index++];
+    EXPECT_EQ(Rule::EQUALS, anyDpiRule->op)
+            << "for " << density << "dpi ANY DPI rule";
+    EXPECT_EQ(Rule::SCREEN_DENSITY, anyDpiRule->key)
+            << "for " << density << "dpi ANY DPI rule";
+    EXPECT_EQ(isAnyDpi == false, anyDpiRule->negate)
+            << "for " << density << "dpi ANY DPI rule";
+    if (anyDpiRule->longArgs.size() == 1) {
+        EXPECT_EQ(ConfigDescription::DENSITY_ANY, anyDpiRule->longArgs[0])
+            << "for " << density << "dpi ANY DPI rule";
+    } else {
+        EXPECT_EQ(1u, anyDpiRule->longArgs.size())
+            << "for " << density << "dpi ANY DPI rule";
+    }
+
+
+    if (greaterThan != 0) {
+        sp<Rule> greaterThanRule = rule->subrules[index++];
+        EXPECT_EQ(Rule::GREATER_THAN, greaterThanRule->op)
+                << "for " << density << "dpi GREATER_THAN rule";
+        EXPECT_EQ(Rule::SCREEN_DENSITY, greaterThanRule->key)
+                << "for " << density << "dpi GREATER_THAN rule";
+        if (greaterThanRule->longArgs.size() == 1) {
+            EXPECT_EQ(greaterThan, greaterThanRule->longArgs[0])
+                << "for " << density << "dpi GREATER_THAN rule";
+        } else {
+            EXPECT_EQ(1u, greaterThanRule->longArgs.size())
+                << "for " << density << "dpi GREATER_THAN rule";
+        }
+    }
+
+    if (lessThan != 0) {
+        sp<Rule> lessThanRule = rule->subrules[index++];
+        EXPECT_EQ(Rule::LESS_THAN, lessThanRule->op)
+                << "for " << density << "dpi LESS_THAN rule";
+        EXPECT_EQ(Rule::SCREEN_DENSITY, lessThanRule->key)
+                << "for " << density << "dpi LESS_THAN rule";
+        if (lessThanRule->longArgs.size() == 1) {
+            EXPECT_EQ(lessThan, lessThanRule->longArgs[0])
+                << "for " << density << "dpi LESS_THAN rule";
+        } else {
+            EXPECT_EQ(1u, lessThanRule->longArgs.size())
+                << "for " << density << "dpi LESS_THAN rule";
+        }
+    }
+}
+
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant,
+        std::initializer_list<const char*> matches) {
+    const abi::Variant* iter = std::find(abis.begin(), abis.end(), variant);
+    if (abis.end() == iter) {
+        ADD_FAILURE() << abi::toString(variant) << " was not in the abi list.";
+        return;
+    }
+
+    sp<Rule> rule = RuleGenerator::generateAbi(abis, iter - abis.begin());
+
+    EXPECT_EQ(Rule::CONTAINS_ANY, rule->op)
+            << "for " << abi::toString(variant) << " rule";
+    EXPECT_EQ(Rule::NATIVE_PLATFORM, rule->key)
+            << " for " << abi::toString(variant) << " rule";
+    EXPECT_EQ(matches.size(), rule->stringArgs.size())
+            << " for " << abi::toString(variant) << " rule";
+
+    for (const char* match : matches) {
+        if (rule->stringArgs.end() ==
+                std::find(rule->stringArgs.begin(), rule->stringArgs.end(), String8(match))) {
+            ADD_FAILURE() << "Rule for abi " << abi::toString(variant)
+                    << " does not contain match for expected abi " << match;
+        }
+    }
+}
+
+} // namespace split
diff --git a/tools/split-select/Rule_test.cpp b/tools/split-select/Rule_test.cpp
new file mode 100644
index 0000000..aca7433
--- /dev/null
+++ b/tools/split-select/Rule_test.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "Rule.h"
+
+#include "SplitDescription.h"
+
+#include <algorithm>
+#include <string>
+#include <gtest/gtest.h>
+#include <utils/String8.h>
+
+using namespace android;
+
+namespace split {
+
+TEST(RuleTest, generatesValidJson) {
+    sp<Rule> rule = new Rule();
+    rule->op = Rule::AND_SUBRULES;
+
+    sp<Rule> subrule = new Rule();
+    subrule->op = Rule::EQUALS;
+    subrule->key = Rule::SDK_VERSION;
+    subrule->longArgs.add(7);
+    rule->subrules.add(subrule);
+
+    subrule = new Rule();
+    subrule->op = Rule::OR_SUBRULES;
+    rule->subrules.add(subrule);
+
+    sp<Rule> subsubrule = new Rule();
+    subsubrule->op = Rule::GREATER_THAN;
+    subsubrule->key = Rule::SCREEN_DENSITY;
+    subsubrule->longArgs.add(10);
+    subrule->subrules.add(subsubrule);
+
+    subsubrule = new Rule();
+    subsubrule->op = Rule::LESS_THAN;
+    subsubrule->key = Rule::SCREEN_DENSITY;
+    subsubrule->longArgs.add(5);
+    subrule->subrules.add(subsubrule);
+
+    std::string expected(
+            "{"
+            "  \"op\": \"AND_SUBRULES\","
+            "  \"subrules\": ["
+            "    {"
+            "      \"op\": \"EQUALS\","
+            "      \"property\": \"SDK_VERSION\","
+            "      \"args\": [7]"
+            "    },"
+            "    {"
+            "      \"op\": \"OR_SUBRULES\","
+            "      \"subrules\": ["
+            "        {"
+            "          \"op\": \"GREATER_THAN\","
+            "          \"property\": \"SCREEN_DENSITY\","
+            "          \"args\": [10]"
+            "        },"
+            "        {"
+            "          \"op\": \"LESS_THAN\","
+            "          \"property\": \"SCREEN_DENSITY\","
+            "          \"args\": [5]"
+            "        }"
+            "      ]"
+            "     }"
+            "  ]"
+            "}");
+    // Trim
+    expected.erase(std::remove_if(expected.begin(), expected.end(), ::isspace), expected.end());
+
+    std::string result(rule->toJson().string());
+
+    // Trim
+    result.erase(std::remove_if(result.begin(), result.end(), ::isspace), result.end());
+
+    ASSERT_EQ(expected, result);
+}
+
+TEST(RuleTest, simplifiesSingleSubruleRules) {
+    sp<Rule> rule = new Rule();
+    rule->op = Rule::AND_SUBRULES;
+
+    sp<Rule> subrule = new Rule();
+    subrule->op = Rule::EQUALS;
+    subrule->key = Rule::SDK_VERSION;
+    subrule->longArgs.add(7);
+    rule->subrules.add(subrule);
+
+    sp<Rule> simplified = Rule::simplify(rule);
+    EXPECT_EQ(Rule::EQUALS, simplified->op);
+    EXPECT_EQ(Rule::SDK_VERSION, simplified->key);
+    ASSERT_EQ(1u, simplified->longArgs.size());
+    EXPECT_EQ(7, simplified->longArgs[0]);
+}
+
+TEST(RuleTest, simplifiesNestedSameOpSubrules) {
+    sp<Rule> rule = new Rule();
+    rule->op = Rule::AND_SUBRULES;
+
+    sp<Rule> subrule = new Rule();
+    subrule->op = Rule::AND_SUBRULES;
+    rule->subrules.add(subrule);
+
+    sp<Rule> subsubrule = new Rule();
+    subsubrule->op = Rule::EQUALS;
+    subsubrule->key = Rule::SDK_VERSION;
+    subsubrule->longArgs.add(7);
+    subrule->subrules.add(subsubrule);
+
+    subrule = new Rule();
+    subrule->op = Rule::EQUALS;
+    subrule->key = Rule::SDK_VERSION;
+    subrule->longArgs.add(8);
+    rule->subrules.add(subrule);
+
+    sp<Rule> simplified = Rule::simplify(rule);
+    EXPECT_EQ(Rule::AND_SUBRULES, simplified->op);
+    ASSERT_EQ(2u, simplified->subrules.size());
+
+    sp<Rule> simplifiedSubrule = simplified->subrules[0];
+    EXPECT_EQ(Rule::EQUALS, simplifiedSubrule->op);
+    EXPECT_EQ(Rule::SDK_VERSION, simplifiedSubrule->key);
+    ASSERT_EQ(1u, simplifiedSubrule->longArgs.size());
+    EXPECT_EQ(7, simplifiedSubrule->longArgs[0]);
+
+    simplifiedSubrule = simplified->subrules[1];
+    EXPECT_EQ(Rule::EQUALS, simplifiedSubrule->op);
+    EXPECT_EQ(Rule::SDK_VERSION, simplifiedSubrule->key);
+    ASSERT_EQ(1u, simplifiedSubrule->longArgs.size());
+    EXPECT_EQ(8, simplifiedSubrule->longArgs[0]);
+}
+
+} // namespace split
diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp
new file mode 100644
index 0000000..8037ef0
--- /dev/null
+++ b/tools/split-select/SplitDescription.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "SplitDescription.h"
+
+#include "aapt/AaptConfig.h"
+#include "aapt/AaptUtil.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+namespace split {
+
+SplitDescription::SplitDescription()
+: abi(abi::Variant::none) {
+}
+
+int SplitDescription::compare(const SplitDescription& rhs) const {
+    int cmp;
+    cmp = (int)abi - (int)rhs.abi;
+    if (cmp != 0) return cmp;
+    return config.compareLogical(rhs.config);
+}
+
+bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescription& target) const {
+    if (abi != abi::Variant::none || o.abi != abi::Variant::none) {
+        abi::Family family = abi::getFamily(abi);
+        abi::Family oFamily = abi::getFamily(o.abi);
+        if (family != oFamily) {
+            return family != abi::Family::none;
+        }
+
+        if (int(target.abi) - int(abi) < int(target.abi) - int(o.abi)) {
+            return true;
+        }
+    }
+    return config.isBetterThan(o.config, &target.config);
+}
+
+bool SplitDescription::match(const SplitDescription& o) const {
+    if (abi != abi::Variant::none) {
+        abi::Family family = abi::getFamily(abi);
+        abi::Family oFamily = abi::getFamily(o.abi);
+        if (family != oFamily) {
+            return false;
+        }
+
+        if (int(abi) > int(o.abi)) {
+            return false;
+        }
+    }
+    return config.match(o.config);
+}
+
+String8 SplitDescription::toString() const {
+    String8 extension;
+    if (abi != abi::Variant::none) {
+        if (extension.isEmpty()) {
+            extension.append(":");
+        } else {
+            extension.append("-");
+        }
+        extension.append(abi::toString(abi));
+    }
+    String8 str(config.toString());
+    str.append(extension);
+    return str;
+}
+
+ssize_t parseAbi(const Vector<String8>& parts, const ssize_t index,
+        SplitDescription* outSplit) {
+    const ssize_t N = parts.size();
+    abi::Variant abi = abi::Variant::none;
+    ssize_t endIndex = index;
+    if (parts[endIndex] == "arm64") {
+        endIndex++;
+        if (endIndex < N) {
+            if (parts[endIndex] == "v8a") {
+                endIndex++;
+                abi = abi::Variant::arm64_v8a;
+            }
+        }
+    } else if (parts[endIndex] == "armeabi") {
+        endIndex++;
+        abi = abi::Variant::armeabi;
+        if (endIndex < N) {
+            if (parts[endIndex] == "v7a") {
+                endIndex++;
+                abi = abi::Variant::armeabi_v7a;
+            }
+        }
+    } else if (parts[endIndex] == "x86") {
+        endIndex++;
+        abi = abi::Variant::x86;
+    } else if (parts[endIndex] == "x86_64") {
+        endIndex++;
+        abi = abi::Variant::x86_64;
+    } else if (parts[endIndex] == "mips") {
+        endIndex++;
+        abi = abi::Variant::mips;
+    } else if (parts[endIndex] == "mips64") {
+        endIndex++;
+        abi = abi::Variant::mips64;
+    }
+
+    if (abi == abi::Variant::none && endIndex != index) {
+        return -1;
+    }
+
+    if (outSplit != NULL) {
+        outSplit->abi = abi;
+    }
+    return endIndex;
+}
+
+bool SplitDescription::parse(const String8& str, SplitDescription* outSplit) {
+    ssize_t index = str.find(":");
+
+    String8 configStr;
+    String8 extensionStr;
+    if (index >= 0) {
+        configStr.setTo(str.string(), index);
+        extensionStr.setTo(str.string() + index + 1);
+    } else {
+        configStr.setTo(str);
+    }
+
+    SplitDescription split;
+    if (!AaptConfig::parse(configStr, &split.config)) {
+        return false;
+    }
+
+    Vector<String8> parts = AaptUtil::splitAndLowerCase(extensionStr, '-');
+    const ssize_t N = parts.size();
+    index = 0;
+
+    if (extensionStr.length() == 0) {
+        goto success;
+    }
+
+    index = parseAbi(parts, index, &split);
+    if (index < 0) {
+        return false;
+    } else {
+        if (index == N) {
+            goto success;
+        }
+    }
+
+    // Unrecognized
+    return false;
+
+success:
+    if (outSplit != NULL) {
+        *outSplit = split;
+    }
+    return true;
+}
+
+} // namespace split
diff --git a/tools/split-select/SplitDescription.h b/tools/split-select/SplitDescription.h
new file mode 100644
index 0000000..5fcafc8
--- /dev/null
+++ b/tools/split-select/SplitDescription.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef H_ANDROID_SPLIT_SPLIT_DESCRIPTION
+#define H_ANDROID_SPLIT_SPLIT_DESCRIPTION
+
+#include "aapt/ConfigDescription.h"
+#include "Abi.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace split {
+
+struct SplitDescription {
+    SplitDescription();
+    SplitDescription(const SplitDescription&) = default;
+
+    ConfigDescription config;
+    abi::Variant abi;
+
+    int compare(const SplitDescription& rhs) const;
+    inline bool operator<(const SplitDescription& rhs) const;
+    inline bool operator==(const SplitDescription& rhs) const;
+    inline bool operator!=(const SplitDescription& rhs) const;
+
+    bool match(const SplitDescription& o) const;
+    bool isBetterThan(const SplitDescription& o, const SplitDescription& target) const;
+
+    android::String8 toString() const;
+
+    static bool parse(const android::String8& str, SplitDescription* outSplit);
+};
+
+ssize_t parseAbi(const android::Vector<android::String8>& parts, const ssize_t index,
+        SplitDescription* outSplit);
+
+bool SplitDescription::operator<(const SplitDescription& rhs) const {
+    return compare(rhs) < 0;
+}
+
+bool SplitDescription::operator==(const SplitDescription& rhs) const {
+    return compare(rhs) == 0;
+}
+
+bool SplitDescription::operator!=(const SplitDescription& rhs) const {
+    return compare(rhs) != 0;
+}
+
+} // namespace split
+
+#endif // H_ANDROID_SPLIT_SPLIT_DESCRIPTION