commit 59c20632a7a86824c5e75e0b24da6efe4f20d48c
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Oct 18 14:06:32 2021 +0200

    Reorg for writing the JSON

diff --git a/src/main/java/org/distorted/objectlib/main/Movement.java b/src/main/java/org/distorted/objectlib/main/Movement.java
index fd4d0357..d005b533 100644
--- a/src/main/java/org/distorted/objectlib/main/Movement.java
+++ b/src/main/java/org/distorted/objectlib/main/Movement.java
@@ -34,6 +34,12 @@ public abstract class Movement
   // each face is split into several parts by lines coming from its center to the vertices
   public static final int TYPE_SPLIT_CORNER = 2;
 
+  public static final int MOVEMENT_HEXAHEDRON   = 0;
+  public static final int MOVEMENT_TETRAHEDRON  = 1;
+  public static final int MOVEMENT_OCTAHEDRON   = 2;
+  public static final int MOVEMENT_DODECAHEDRON = 3;
+  public static final int MOVEMENT_SHAPECHANGE  = 4;
+
   static final float SQ3 = (float)Math.sqrt(3);
   static final float SQ6 = (float)Math.sqrt(6);
 
diff --git a/src/main/java/org/distorted/objectlib/main/ObjectType.java b/src/main/java/org/distorted/objectlib/main/ObjectType.java
index 6a0504bd..e439ab17 100644
--- a/src/main/java/org/distorted/objectlib/main/ObjectType.java
+++ b/src/main/java/org/distorted/objectlib/main/ObjectType.java
@@ -122,13 +122,6 @@ public enum ObjectType
     return -1;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static int getNumScramble(int ordinal)
-    {
-    return ordinal>=0 && ordinal<NUM_OBJECTS ? objects[ordinal].mNumScrambles : 0;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   ObjectType(int[] numLayers, int scrambles, int sIcon, int mIcon, int bIcon, int hIcon)
@@ -141,6 +134,13 @@ public enum ObjectType
     mHugeIcon    = hIcon;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getNumScramble()
+    {
+    return mNumScrambles;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getIconID(int size)
diff --git a/src/main/java/org/distorted/objectlib/main/TwistyObject.java b/src/main/java/org/distorted/objectlib/main/TwistyObject.java
index 8545e7ea..39bbec32 100644
--- a/src/main/java/org/distorted/objectlib/main/TwistyObject.java
+++ b/src/main/java/org/distorted/objectlib/main/TwistyObject.java
@@ -60,6 +60,12 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.Random;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_TETRAHEDRON;
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
+import static org.distorted.objectlib.main.Movement.MOVEMENT_OCTAHEDRON;
+import static org.distorted.objectlib.main.Movement.MOVEMENT_DODECAHEDRON;
+import static org.distorted.objectlib.main.Movement.MOVEMENT_SHAPECHANGE;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public abstract class TwistyObject extends DistortedNode
@@ -107,7 +113,7 @@ public abstract class TwistyObject extends DistortedNode
   private final Static3D mNodeScale;
   private final Static4D mQuat;
   private final int[] mNumLayers;
-  private final float mRealSize;
+  private final float mSize;
   private final DistortedEffects mEffects;
   private final VertexEffectRotate mRotateEffect;
   private final Dynamic1D mRotationAngle;
@@ -126,9 +132,12 @@ public abstract class TwistyObject extends DistortedNode
   private int[] mTmpQuats;
   private int mNumTexRows, mNumTexCols;
   private int mRotRowBitmap;
-  private int mRotAxis;
+  private int mCurrentRotAxis;
   private MeshBase mMesh;
   private final TwistyObjectScrambler mScrambler;
+  private Movement mMovement;
+  private boolean[][] mLayerRotatable;
+  private int[][][] mEnabled;
 
   //////////////////// SOLVED1 ////////////////////////
 
@@ -138,7 +147,7 @@ public abstract class TwistyObject extends DistortedNode
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  TwistyObject(int[] numLayers, float realSize, Static4D quat, Static3D move, DistortedTexture nodeTexture,
+  TwistyObject(int[] numLayers, float size, Static4D quat, Static3D move, DistortedTexture nodeTexture,
                MeshSquare nodeMesh, DistortedEffects nodeEffects, Resources res, int surfaceW, int surfaceH)
     {
     super(nodeTexture,nodeEffects,nodeMesh);
@@ -149,7 +158,7 @@ public abstract class TwistyObject extends DistortedNode
     resizeFBO(mNodeW,mNodeH);
 
     mNumLayers = numLayers;
-    mRealSize = realSize;
+    mSize = size;
     mOrigPos = getCubitPositions(mNumLayers);
     mAxis = getRotationAxis();
     mInitScreenRatio = getScreenRatio();
@@ -907,16 +916,16 @@ public abstract class TwistyObject extends DistortedNode
     double nearestAngleInRadians = angle*Math.PI/180;
     float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
     float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
-    float axisX = mAxis[mRotAxis].get0();
-    float axisY = mAxis[mRotAxis].get1();
-    float axisZ = mAxis[mRotAxis].get2();
+    float axisX = mAxis[mCurrentRotAxis].get0();
+    float axisY = mAxis[mCurrentRotAxis].get1();
+    float axisZ = mAxis[mCurrentRotAxis].get2();
     Static4D quat = new Static4D( axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
 
     mRotationAngle.removeAll();
     mRotationAngleStatic.set0(0);
 
     for(int i=0; i<NUM_CUBITS; i++)
-      if( belongsToRotation(i,mRotAxis,mRotRowBitmap) )
+      if( belongsToRotation(i, mCurrentRotAxis,mRotRowBitmap) )
         {
         int index = CUBITS[i].removeRotationNow(quat);
         mMesh.setEffectAssociation(i, CUBITS[i].computeAssociation(),index);
@@ -954,7 +963,7 @@ public abstract class TwistyObject extends DistortedNode
     {
     if( wasRotateApplied() )
       {
-      mRotAxis     = axis;
+      mCurrentRotAxis = axis;
       mRotRowBitmap= computeBitmapFromRow( rowBitmap,axis );
 
       mRotationAngleStatic.set0(0.0f);
@@ -994,7 +1003,7 @@ public abstract class TwistyObject extends DistortedNode
       return;
       }
 
-    mRotAxis     = axis;
+    mCurrentRotAxis = axis;
     mRotRowBitmap= computeBitmapFromRow( (1<<row),axis );
     mRotationAngleStatic.set0(0.0f);
     mRotationAxis.set( mAxis[axis] );
@@ -1144,7 +1153,7 @@ public abstract class TwistyObject extends DistortedNode
     {
     mObjectScreenRatio = sc;
     int nodeMinSize = Math.min(mNodeW,mNodeH);
-    float scale = mObjectScreenRatio*mInitScreenRatio*nodeMinSize/mRealSize;
+    float scale = mObjectScreenRatio*mInitScreenRatio*nodeMinSize/mSize;
     mObjectScale.set(scale,scale,scale);
     }
 
@@ -1255,9 +1264,16 @@ public abstract class TwistyObject extends DistortedNode
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public Static4D getRotationQuat()
-      {
-      return mQuat;
-      }
+    {
+    return mQuat;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float getSize()
+    {
+    return mSize;
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -1326,6 +1342,38 @@ public abstract class TwistyObject extends DistortedNode
     return intGetObjectType(mNumLayers);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public Movement getMovement()
+    {
+    if( mMovement==null )
+      {
+      int[] numLayers = getNumLayers();
+      if( mCuts==null ) getCuts(numLayers);
+      if( mLayerRotatable==null ) mLayerRotatable = getLayerRotatable(numLayers);
+      if( mEnabled==null ) mEnabled = getEnabled();
+
+      int movementType = getMovementType();
+      int movementSplit= getMovementSplit();
+
+      switch(movementType)
+        {
+        case MOVEMENT_TETRAHEDRON : mMovement = new Movement4(mAxis,mCuts,mLayerRotatable,mSize,movementSplit,mEnabled);
+                                    break;
+        case MOVEMENT_HEXAHEDRON  : mMovement = new Movement6(mAxis,mCuts,mLayerRotatable,mSize,movementSplit,mEnabled);
+                                    break;
+        case MOVEMENT_OCTAHEDRON  : mMovement = new Movement8(mAxis,mCuts,mLayerRotatable,mSize,movementSplit,mEnabled);
+                                    break;
+        case MOVEMENT_DODECAHEDRON: mMovement = new Movement12(mAxis,mCuts,mLayerRotatable,mSize,movementSplit,mEnabled);
+                                    break;
+        case MOVEMENT_SHAPECHANGE : float[] dist3D = getDist3D(numLayers);
+                                    mMovement = new MovementC(mAxis,mCuts,mLayerRotatable,mSize,movementSplit,mEnabled,dist3D);
+                                    break;
+        }
+      }
+    return mMovement;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   protected abstract int getFOV();
@@ -1341,19 +1389,26 @@ public abstract class TwistyObject extends DistortedNode
   protected abstract Static4D getQuat(int cubit, int[] numLayers);
   protected abstract ObjectShape getObjectShape(int cubit, int[] numLayers);
   protected abstract int[] getSolvedQuats(int cubit, int[] numLayers);
-  protected abstract int getSolvedFunctionIndex();
   protected abstract ScrambleState[] getScrambleStates();
   protected abstract int getNumStickerTypes(int[] numLayers);
   protected abstract ObjectSticker retSticker(int face);
   protected abstract int getFaceColor(int cubit, int cubitface, int[] numLayers);
   protected abstract int getResource(int[] numLayers);
   protected abstract ObjectType intGetObjectType(int[] numLayers);
-  protected abstract Movement getMovement();
+
+  // for JSON only
+  public abstract int getSolvedFunctionIndex();
+  public abstract int getMovementType();
+  public abstract int getMovementSplit();
+  public abstract boolean[][] getLayerRotatable(int[] numLayers);
+  public abstract int[][][] getEnabled();
+  public abstract float[] getDist3D(int[] numLayers);
 
   public abstract Static3D[] getRotationAxis();
   public abstract int[] getBasicAngle();
   public abstract int getNumFaces();
   public abstract int getObjectName(int[] numLayers);
   public abstract int getInventor(int[] numLayers);
+  public abstract int getYearOfInvention(int[] numLayers);
   public abstract int getComplexity(int[] numLayers);
   }
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyBandaged2Bar.java b/src/main/java/org/distorted/objectlib/objects/TwistyBandaged2Bar.java
index fa905bf1..36564ab9 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyBandaged2Bar.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyBandaged2Bar.java
@@ -135,6 +135,13 @@ public class TwistyBandaged2Bar extends TwistyBandagedAbstract
     return R.string.bandaged_2bar_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2000;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyBandaged3Plate.java b/src/main/java/org/distorted/objectlib/objects/TwistyBandaged3Plate.java
index db7b3c0c..61b7bb0c 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyBandaged3Plate.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyBandaged3Plate.java
@@ -142,6 +142,13 @@ public class TwistyBandaged3Plate extends TwistyBandagedAbstract
     return R.string.bandaged_3plate_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2000;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyBandagedAbstract.java b/src/main/java/org/distorted/objectlib/objects/TwistyBandagedAbstract.java
index cb7d1b05..00d88acb 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyBandagedAbstract.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyBandagedAbstract.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_NOT_SPLIT;
 
 import android.content.res.Resources;
@@ -29,7 +30,6 @@ import org.distorted.library.mesh.MeshSquare;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.helpers.ObjectShape;
 import org.distorted.objectlib.helpers.ObjectSticker;
@@ -58,11 +58,6 @@ abstract class TwistyBandagedAbstract extends Twisty6
          {2,2,2}
         };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}},
-      };
-
   private static final int NUM_STICKERS = 4;
 
   private int[] mBasicAngle;
@@ -72,8 +67,6 @@ abstract class TwistyBandagedAbstract extends Twisty6
   private int[][] mAxisMap;
   private int[][] mFaceMap;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
-  private Movement mMovement;
   ScrambleState[] mStates;
   float[][] POSITIONS;
   int[] QUAT_INDICES;
@@ -355,24 +348,54 @@ abstract class TwistyBandagedAbstract extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
       }
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_HEXAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_NOT_SPLIT;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int[][][] getEnabled()
+    {
+    return new int[][][]
+      {
+          {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}},
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -471,20 +494,6 @@ abstract class TwistyBandagedAbstract extends Twisty6
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_NOT_SPLIT,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyBandagedEvil.java b/src/main/java/org/distorted/objectlib/objects/TwistyBandagedEvil.java
index edce1b45..138c6b95 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyBandagedEvil.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyBandagedEvil.java
@@ -266,6 +266,13 @@ public class TwistyBandagedEvil extends TwistyBandagedAbstract
     return R.string.bandaged_evil_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2000;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyBandagedFused.java b/src/main/java/org/distorted/objectlib/objects/TwistyBandagedFused.java
index e0db70ba..0c88cafb 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyBandagedFused.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyBandagedFused.java
@@ -135,6 +135,13 @@ public class TwistyBandagedFused extends TwistyBandagedAbstract
     return R.string.bandaged_fused_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2000;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyCuboid.java b/src/main/java/org/distorted/objectlib/objects/TwistyCuboid.java
index 8505c53d..53390d49 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyCuboid.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyCuboid.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_SHAPECHANGE;
 import static org.distorted.objectlib.main.Movement.TYPE_NOT_SPLIT;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.MovementC;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -50,18 +50,11 @@ public class TwistyCuboid extends Twisty6
            new Static3D(0,0,1)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}},
-      };
-
   private ScrambleState[] mStates;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private int[] mBasicAngle;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -564,62 +557,51 @@ public class TwistyCuboid extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
       }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
-    {
-    return 0;
+    return layerRotatable;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getNumStickerTypes(int[] numLayers)
+  public int getMovementType()
     {
-    return 1;
+    return MOVEMENT_SHAPECHANGE;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getNumCubitFaces()
+  public int getMovementSplit()
     {
-    return 6;
+    return TYPE_NOT_SPLIT;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
 
-  public Static3D[] getRotationAxis()
+  public int[][][] getEnabled()
     {
-    return ROT_AXIS;
+    return new int[][][]
+      {
+          {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}},
+      };
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public Movement getMovement()
+  public float[] getDist3D(int[] numLayers)
     {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      float avg = (numLayers[0]+numLayers[1]+numLayers[2])/3.0f;
+    float avg = (numLayers[0]+numLayers[1]+numLayers[2])/3.0f;
 
-      float[] dist3D =
+    return new float[]
         {
         0.5f*numLayers[0]/avg,
         0.5f*numLayers[0]/avg,
@@ -628,10 +610,35 @@ public class TwistyCuboid extends Twisty6
         0.5f*numLayers[2]/avg,
         0.5f*numLayers[2]/avg,
         };
+    }
 
-      mMovement = new MovementC(ROT_AXIS,mCuts,mLayerRotatable,avg,TYPE_NOT_SPLIT,ENABLED,dist3D);
-      }
-    return mMovement;
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getSolvedFunctionIndex()
+    {
+    return 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  protected int getNumStickerTypes(int[] numLayers)
+    {
+    return 1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  protected int getNumCubitFaces()
+    {
+    return 6;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public Static3D[] getRotationAxis()
+    {
+    return ROT_AXIS;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -705,6 +712,20 @@ public class TwistyCuboid extends Twisty6
     return R.string.cube3_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    switch(numLayers[0])
+      {
+      case 2: return 1970;
+      case 3: return 1974;
+      case 4: return 1981;
+      case 5: return 1981;
+      }
+    return 1974;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyDiamond.java b/src/main/java/org/distorted/objectlib/objects/TwistyDiamond.java
index db2bb8b4..a4c9c098 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyDiamond.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyDiamond.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_OCTAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_NOT_SPLIT;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement8;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -52,20 +52,13 @@ public class TwistyDiamond extends Twisty8
            new Static3D(     0,-SQ3/3,+SQ6/3)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{1,2,3}},{{1,2,3}},{{0,2,3}},{{0,2,3}},{{0,1,3}},{{0,1,3}},{{0,1,2}},{{0,1,2}}
-      };
-
   private ScrambleState[] mStates;
   private int[] mBasicAngle;
   private int[] mFaceMap;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private Static4D[] mQuats;
   private int[] mTetraToFaceMap;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -157,7 +150,7 @@ public class TwistyDiamond extends Twisty8
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -196,19 +189,49 @@ public class TwistyDiamond extends Twisty8
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
       }
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_OCTAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_NOT_SPLIT;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][]
+      {
+          {{1,2,3}},{{1,2,3}},{{0,2,3}},{{0,2,3}},{{0,1,3}},{{0,1,3}},{{0,1,2}},{{0,1,2}}
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -539,20 +562,6 @@ public class TwistyDiamond extends Twisty8
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement8(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_NOT_SPLIT,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -603,6 +612,19 @@ public class TwistyDiamond extends Twisty8
     return 0;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    switch(numLayers[0])
+      {
+      case 2: return 1984;
+      case 3: return 2003;
+      case 4: return 2011;
+      }
+    return 1984;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyDino.java b/src/main/java/org/distorted/objectlib/objects/TwistyDino.java
index a642850e..4813caef 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyDino.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyDino.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_SPLIT_CORNER;
 
 import android.content.res.Resources;
@@ -30,8 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
-import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.helpers.ObjectShape;
 import org.distorted.objectlib.helpers.ObjectSticker;
 import org.distorted.objectlib.helpers.ScrambleState;
@@ -51,23 +50,11 @@ abstract class TwistyDino extends Twisty6
            new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{0,1},{3,1},{2,3},{0,2}},
-          {{2,3},{3,1},{0,1},{0,2}},
-          {{1,2},{0,1},{0,3},{2,3}},
-          {{1,2},{2,3},{0,3},{0,1}},
-          {{0,3},{0,2},{1,2},{1,3}},
-          {{1,2},{0,2},{0,3},{1,3}},
-      };
-
   private int[] mBasicAngle;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private ObjectSticker[] mStickers;
   private float[][] mCenters;
-  private Movement mMovement;
   ScrambleState[] mStates;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -129,15 +116,50 @@ abstract class TwistyDino extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
+    int numAxis = ROT_AXIS.length;
+    boolean[] tmp = new boolean[] {true,false,true};
+    boolean[][] layerRotatable = new boolean[numAxis][];
+    for(int i=0; i<numAxis; i++) layerRotatable[i] = tmp;
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_HEXAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_SPLIT_CORNER;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][]
       {
-      int numAxis = ROT_AXIS.length;
-      boolean[] tmp = new boolean[] {true,false,true};
-      mLayerRotatable = new boolean[numAxis][];
-      for(int i=0; i<numAxis; i++) mLayerRotatable[i] = tmp;
-      }
+          {{0,1},{3,1},{2,3},{0,2}},
+          {{2,3},{3,1},{0,1},{0,2}},
+          {{1,2},{0,1},{0,3},{2,3}},
+          {{1,2},{2,3},{0,3},{0,1}},
+          {{0,3},{0,2},{1,2},{1,3}},
+          {{1,2},{0,2},{0,3},{1,3}},
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -248,20 +270,6 @@ abstract class TwistyDino extends Twisty6
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_SPLIT_CORNER,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyDino4.java b/src/main/java/org/distorted/objectlib/objects/TwistyDino4.java
index c94d026c..e710af0e 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyDino4.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyDino4.java
@@ -85,7 +85,7 @@ public class TwistyDino4 extends TwistyDino
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 1;
     }
@@ -117,4 +117,11 @@ public class TwistyDino4 extends TwistyDino
     {
     return R.string.din43_inventor;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 1985;
+    }
 }
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyDino6.java b/src/main/java/org/distorted/objectlib/objects/TwistyDino6.java
index d5a3cce0..27091002 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyDino6.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyDino6.java
@@ -94,7 +94,7 @@ public class TwistyDino6 extends TwistyDino
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 2;
     }
@@ -119,4 +119,11 @@ public class TwistyDino6 extends TwistyDino
     {
     return R.string.dino3_inventor;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 1985;
+    }
 }
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyHelicopter.java b/src/main/java/org/distorted/objectlib/objects/TwistyHelicopter.java
index db3e7d75..7cabf2c8 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyHelicopter.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyHelicopter.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_SPLIT_EDGE;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -54,26 +54,14 @@ public class TwistyHelicopter extends Twisty6
            new Static3D(-SQ2/2, -SQ2/2,      0)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{2,5},{2,4},{3,4},{3,5}},
-          {{2,4},{2,5},{3,5},{3,4}},
-          {{0,5},{1,5},{1,4},{0,4}},
-          {{0,4},{1,4},{1,5},{0,5}},
-          {{1,3},{0,3},{0,2},{1,2}},
-          {{0,3},{1,3},{1,2},{0,2}},
-      };
-
   private ScrambleState[] mStates;
   private int[] mBasicAngle;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private float[][] mCenters;
   private int[] mQuatIndices;
   private int[][] mFaceMap;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -171,7 +159,7 @@ public class TwistyHelicopter extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -198,15 +186,50 @@ public class TwistyHelicopter extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
+    {
+    int numAxis = ROT_AXIS.length;
+    boolean[] tmp = new boolean[] {true,false,true};
+    boolean[][] layerRotatable = new boolean[numAxis][];
+    for(int i=0; i<numAxis; i++) layerRotatable[i] = tmp;
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_HEXAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_SPLIT_EDGE;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
     {
-    if( mLayerRotatable==null )
+    return new int[][][]
       {
-      int numAxis = ROT_AXIS.length;
-      boolean[] tmp = new boolean[] {true,false,true};
-      mLayerRotatable = new boolean[numAxis][];
-      for(int i=0; i<numAxis; i++) mLayerRotatable[i] = tmp;
-      }
+          {{2,5},{2,4},{3,4},{3,5}},
+          {{2,4},{2,5},{3,5},{3,4}},
+          {{0,5},{1,5},{1,4},{0,4}},
+          {{0,4},{1,4},{1,5},{0,5}},
+          {{1,3},{0,3},{0,2},{1,2}},
+          {{0,3},{1,3},{1,2},{0,2}},
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -441,20 +464,6 @@ public class TwistyHelicopter extends Twisty6
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_SPLIT_EDGE,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -484,6 +493,13 @@ public class TwistyHelicopter extends Twisty6
     return R.string.heli3_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2006;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyIvy.java b/src/main/java/org/distorted/objectlib/objects/TwistyIvy.java
index d5e15f06..1d76386f 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyIvy.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyIvy.java
@@ -20,6 +20,7 @@
 package org.distorted.objectlib.objects;
 
 import static org.distorted.objectlib.main.Movement.TYPE_SPLIT_CORNER;
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 
 import android.content.res.Resources;
 
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -51,16 +51,6 @@ public class TwistyIvy extends Twisty6
            new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{0},{3},{3},{0}},
-          {{2},{1},{1},{2}},
-          {{2},{0},{0},{2}},
-          {{1},{3},{3},{1}},
-          {{0},{0},{1},{1}},
-          {{2},{2},{3},{3}},
-      };
-
   private static final int NUM_STICKERS = 2;
   public static final float IVY_D = 0.006f;
   private static final int  IVY_N = 8;
@@ -69,10 +59,8 @@ public class TwistyIvy extends Twisty6
   private int[] mBasicAngle;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private int[][] mFaceMap;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -147,7 +135,7 @@ public class TwistyIvy extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -174,19 +162,54 @@ public class TwistyIvy extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
       }
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_HEXAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_SPLIT_CORNER;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][]
+      {
+          {{0},{3},{3},{0}},
+          {{2},{1},{1},{2}},
+          {{2},{0},{0},{2}},
+          {{1},{3},{3},{1}},
+          {{0},{0},{1},{1}},
+          {{2},{2},{3},{3}},
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -473,20 +496,6 @@ public class TwistyIvy extends Twisty6
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_SPLIT_CORNER,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -516,6 +525,13 @@ public class TwistyIvy extends Twisty6
     return R.string.ivy2_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2009;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyJing.java b/src/main/java/org/distorted/objectlib/objects/TwistyJing.java
index 5069b41c..f43702d4 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyJing.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyJing.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_TETRAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_NOT_SPLIT;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement4;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -51,11 +51,6 @@ public class TwistyJing extends Twisty4
            new Static3D(-SQ6/3,+SQ3/3,     0),
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{1,2,3}},{{0,2,3}},{{0,1,3}},{{0,1,2}}
-      };
-
   static final float F = 0.48f;  // length of the edge of the corner cubit. Keep<0.5
                                  // Assuming the length of the edge of the whole
                                  // tetrahedron is 2.0 (ie standard, equal to numLayers
@@ -65,11 +60,9 @@ public class TwistyJing extends Twisty4
   private int[] mRotQuat;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private float[][] mCenters;
   private int[][] mFaceMap;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -173,7 +166,7 @@ public class TwistyJing extends Twisty4
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -200,19 +193,49 @@ public class TwistyJing extends Twisty4
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
       }
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_TETRAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_NOT_SPLIT;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][]
+      {
+          {{1,2,3}},{{0,2,3}},{{0,1,3}},{{0,1,2}}
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -431,20 +454,6 @@ public class TwistyJing extends Twisty4
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement4(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_NOT_SPLIT,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -474,6 +483,13 @@ public class TwistyJing extends Twisty4
     return R.string.jing_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 1991;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyKilominx.java b/src/main/java/org/distorted/objectlib/objects/TwistyKilominx.java
index e226128e..040caa63 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyKilominx.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyKilominx.java
@@ -752,6 +752,18 @@ public class TwistyKilominx extends TwistyMinx
     return 0;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    switch(numLayers[0])
+      {
+      case 3: return 2008;
+      case 5: return 2010;
+      }
+    return 2008;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyMegaminx.java b/src/main/java/org/distorted/objectlib/objects/TwistyMegaminx.java
index e7e4c08a..3be562f1 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyMegaminx.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyMegaminx.java
@@ -654,6 +654,18 @@ public class TwistyMegaminx extends TwistyMinx
     return 0;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    switch(numLayers[0])
+      {
+      case 3: return 1982;
+      case 5: return 2006;
+      }
+    return 1982;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyMinx.java b/src/main/java/org/distorted/objectlib/objects/TwistyMinx.java
index 9bc5bbce..8dd45d37 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyMinx.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyMinx.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_DODECAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_SPLIT_EDGE;
 import static org.distorted.objectlib.main.Movement12.C2;
 import static org.distorted.objectlib.main.Movement12.LEN;
@@ -31,7 +32,6 @@ import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshSquare;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement12;
 import org.distorted.objectlib.helpers.ObjectSticker;
 import org.distorted.objectlib.helpers.ScrambleState;
@@ -61,28 +61,10 @@ abstract class TwistyMinx extends Twisty12
            new Static3D( SIN54/LEN,    0     ,   -C2/LEN )
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{2,3},{3,5},{1,5},{1,4},{2,4}},
-          {{0,5},{2,5},{2,3},{3,4},{0,4}},
-          {{2,3},{2,5},{0,5},{0,4},{3,4}},
-          {{1,5},{3,5},{2,3},{2,4},{1,4}},
-          {{0,3},{0,4},{4,5},{1,5},{1,3}},
-          {{1,2},{1,4},{4,5},{0,5},{0,2}},
-          {{4,5},{1,4},{1,2},{0,2},{0,5}},
-          {{4,5},{0,4},{0,3},{1,3},{1,5}},
-          {{0,2},{0,1},{1,3},{3,5},{2,5}},
-          {{3,4},{2,4},{1,2},{0,1},{0,3}},
-          {{2,4},{3,4},{0,3},{0,1},{1,2}},
-          {{1,3},{0,1},{0,2},{2,5},{3,5}},
-      };
-
   private ScrambleState[] mStates;
   private int[] mBasicAngle;
   private int[] mFaceMap;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
-  private Movement mMovement;
   Static4D[] mQuats;
   float[][] mCenterCoords;
   float[][] mCorners;
@@ -566,57 +548,83 @@ abstract class TwistyMinx extends Twisty12
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        mLayerRotatable[i][numLayers[i]/2] = false;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
+      layerRotatable[i][numLayers[i]/2] = false;
       }
+
+    return layerRotatable;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getMovementType()
     {
-    return 0;
+    return MOVEMENT_DODECAHEDRON;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getNumCubitFaces()
+  public int getMovementSplit()
     {
-    return 6;
+    return TYPE_SPLIT_EDGE;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
 
-  public Static3D[] getRotationAxis()
+  public int[][][] getEnabled()
     {
-    return ROT_AXIS;
+    return new int[][][]
+      {
+          {{2,3},{3,5},{1,5},{1,4},{2,4}},
+          {{0,5},{2,5},{2,3},{3,4},{0,4}},
+          {{2,3},{2,5},{0,5},{0,4},{3,4}},
+          {{1,5},{3,5},{2,3},{2,4},{1,4}},
+          {{0,3},{0,4},{4,5},{1,5},{1,3}},
+          {{1,2},{1,4},{4,5},{0,5},{0,2}},
+          {{4,5},{1,4},{1,2},{0,2},{0,5}},
+          {{4,5},{0,4},{0,3},{1,3},{1,5}},
+          {{0,2},{0,1},{1,3},{3,5},{2,5}},
+          {{3,4},{2,4},{1,2},{0,1},{0,3}},
+          {{2,4},{3,4},{0,3},{0,1},{1,2}},
+          {{1,3},{0,1},{0,2},{2,5},{3,5}},
+      };
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public Movement getMovement()
+  public float[] getDist3D(int[] numLayers)
     {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement12(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_SPLIT_EDGE,ENABLED);
-      }
+    return null;
+    }
 
-    return mMovement;
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getSolvedFunctionIndex()
+    {
+    return 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  protected int getNumCubitFaces()
+    {
+    return 6;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public Static3D[] getRotationAxis()
+    {
+    return ROT_AXIS;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyMirror.java b/src/main/java/org/distorted/objectlib/objects/TwistyMirror.java
index 3380a90c..97e11897 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyMirror.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyMirror.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_NOT_SPLIT;
 
 import android.content.res.Resources;
@@ -30,8 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
-import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
 import org.distorted.objectlib.helpers.ObjectShape;
@@ -50,11 +49,6 @@ public class TwistyMirror extends Twisty6
            new Static3D(0,0,1)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}},
-      };
-
   private static final int[] FACE_COLORS = new int[] { COLOR_WHITE };
   private static final float DX = 0.10f;
   private static final float DY = 0.25f;
@@ -79,11 +73,9 @@ public class TwistyMirror extends Twisty6
   private ScrambleState[] mStates;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private int[] mBasicAngle;
   private ObjectSticker[] mStickers;
   private float[][] mPositions;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -586,24 +578,54 @@ public class TwistyMirror extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
       }
+
+    return layerRotatable;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getMovementType()
+    {
+    return MOVEMENT_HEXAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_NOT_SPLIT;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][]
+      {
+          {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}},
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -623,20 +645,6 @@ public class TwistyMirror extends Twisty6
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_NOT_SPLIT,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -682,6 +690,18 @@ public class TwistyMirror extends Twisty6
     return R.string.mirr3_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    switch(numLayers[0])
+      {
+      case 2: return 2007;
+      case 3: return 2006;
+      }
+    return 2006;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyPyraminx.java b/src/main/java/org/distorted/objectlib/objects/TwistyPyraminx.java
index 7d30a728..c34e469e 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyPyraminx.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyPyraminx.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_TETRAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_NOT_SPLIT;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement4;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -51,18 +51,11 @@ public class TwistyPyraminx extends Twisty4
            new Static3D(-SQ6/3,+SQ3/3,     0),
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{1,2,3}},{{0,2,3}},{{0,1,3}},{{0,1,2}}
-      };
-
   private ScrambleState[] mStates;
   private int[] mBasicAngle;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -228,7 +221,7 @@ public class TwistyPyraminx extends Twisty4
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -264,19 +257,46 @@ public class TwistyPyraminx extends Twisty4
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
       }
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_TETRAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_NOT_SPLIT;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][] { {{1,2,3}},{{0,2,3}},{{0,1,3}},{{0,1,2}} };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -422,20 +442,6 @@ public class TwistyPyraminx extends Twisty4
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement4(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_NOT_SPLIT,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -484,6 +490,19 @@ public class TwistyPyraminx extends Twisty4
     return R.string.pyra3_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    switch(numLayers[0])
+      {
+      case 3: return 1970;
+      case 4: return 2002;
+      case 5: return 2011;
+      }
+    return 1970;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyRedi.java b/src/main/java/org/distorted/objectlib/objects/TwistyRedi.java
index 9e51d1da..13c8e0de 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyRedi.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyRedi.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_SPLIT_CORNER;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -51,25 +51,13 @@ public class TwistyRedi extends Twisty6
            new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{0,1},{3,1},{2,3},{0,2}},
-          {{2,3},{3,1},{0,1},{0,2}},
-          {{1,2},{0,1},{0,3},{2,3}},
-          {{1,2},{2,3},{0,3},{0,1}},
-          {{0,3},{0,2},{1,2},{1,3}},
-          {{1,2},{0,2},{0,3},{1,3}},
-      };
-
   private ScrambleState[] mStates;
   private int[] mBasicAngle;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private float[][] mCenters;
   private int[][] mFaceMap;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -150,7 +138,7 @@ public class TwistyRedi extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -178,15 +166,50 @@ public class TwistyRedi extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
+    {
+    int numAxis = ROT_AXIS.length;
+    boolean[] tmp = new boolean[] {true,false,true};
+    boolean[][] layerRotatable = new boolean[numAxis][];
+    for(int i=0; i<numAxis; i++) layerRotatable[i] = tmp;
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_HEXAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
     {
-    if( mLayerRotatable==null )
+    return TYPE_SPLIT_CORNER;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][]
       {
-      int numAxis = ROT_AXIS.length;
-      boolean[] tmp = new boolean[] {true,false,true};
-      mLayerRotatable = new boolean[numAxis][];
-      for(int i=0; i<numAxis; i++) mLayerRotatable[i] = tmp;
-      }
+          {{0,1},{3,1},{2,3},{0,2}},
+          {{2,3},{3,1},{0,1},{0,2}},
+          {{1,2},{0,1},{0,3},{2,3}},
+          {{1,2},{2,3},{0,3},{0,1}},
+          {{0,3},{0,2},{1,2},{1,3}},
+          {{1,2},{0,2},{0,3},{1,3}},
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -439,20 +462,6 @@ public class TwistyRedi extends Twisty6
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_SPLIT_CORNER,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -482,6 +491,13 @@ public class TwistyRedi extends Twisty6
     return R.string.redi2_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2009;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyRex.java b/src/main/java/org/distorted/objectlib/objects/TwistyRex.java
index 2f3911a4..ec3eae6f 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyRex.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyRex.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_SPLIT_CORNER;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -51,26 +51,14 @@ public class TwistyRex extends Twisty6
            new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{0,1},{3,1},{2,3},{0,2}},
-          {{2,3},{3,1},{0,1},{0,2}},
-          {{1,2},{0,1},{0,3},{2,3}},
-          {{1,2},{2,3},{0,3},{0,1}},
-          {{0,3},{0,2},{1,2},{1,3}},
-          {{1,2},{0,2},{0,3},{1,3}},
-      };
-
   public static final float REX_D = 0.2f;
 
   private ScrambleState[] mStates;
   private int[] mBasicAngle;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private int[][] mFaceMap;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -145,7 +133,7 @@ public class TwistyRex extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -173,15 +161,50 @@ public class TwistyRex extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
+    {
+    int numAxis = ROT_AXIS.length;
+    boolean[] tmp = new boolean[] {true,false,true};
+    boolean[][] layerRotatable = new boolean[numAxis][];
+    for(int i=0; i<numAxis; i++) layerRotatable[i] = tmp;
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_HEXAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_SPLIT_CORNER;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
     {
-    if( mLayerRotatable==null )
+    return new int[][][]
       {
-      int numAxis = ROT_AXIS.length;
-      boolean[] tmp = new boolean[] {true,false,true};
-      mLayerRotatable = new boolean[numAxis][];
-      for(int i=0; i<numAxis; i++) mLayerRotatable[i] = tmp;
-      }
+          {{0,1},{3,1},{2,3},{0,2}},
+          {{2,3},{3,1},{0,1},{0,2}},
+          {{1,2},{0,1},{0,3},{2,3}},
+          {{1,2},{2,3},{0,3},{0,1}},
+          {{0,3},{0,2},{1,2},{1,3}},
+          {{1,2},{0,2},{0,3},{1,3}},
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -473,20 +496,6 @@ public class TwistyRex extends Twisty6
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_SPLIT_CORNER,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -516,6 +525,13 @@ public class TwistyRex extends Twisty6
     return R.string.rex3_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2009;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistySkewb.java b/src/main/java/org/distorted/objectlib/objects/TwistySkewb.java
index c47e1900..32ac3daf 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistySkewb.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistySkewb.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_SPLIT_CORNER;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -51,24 +51,12 @@ public class TwistySkewb extends Twisty6
            new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-      {
-          {{0,1},{3,1},{2,3},{0,2}},
-          {{2,3},{3,1},{0,1},{0,2}},
-          {{1,2},{0,1},{0,3},{2,3}},
-          {{1,2},{2,3},{0,3},{0,1}},
-          {{0,3},{0,2},{1,2},{1,3}},
-          {{1,2},{0,2},{0,3},{1,3}},
-      };
-
   private ScrambleState[] mStates;
   private int[] mBasicAngle;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private int[][] mCornerMap,mEdgeMap,mCenterMap;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -173,7 +161,7 @@ public class TwistySkewb extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -200,15 +188,50 @@ public class TwistySkewb extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
+    {
+    int numAxis = ROT_AXIS.length;
+    boolean[] tmp = numLayers[0]==2 ? (new boolean[] {true,true}) : (new boolean[] {true,false,true});
+    boolean[][] layerRotatable = new boolean[numAxis][];
+    for(int i=0; i<numAxis; i++) layerRotatable[i] = tmp;
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_HEXAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_SPLIT_CORNER;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
     {
-    if( mLayerRotatable==null )
+    return new int[][][]
       {
-      int numAxis = ROT_AXIS.length;
-      boolean[] tmp = numLayers[0]==2 ? (new boolean[] {true,true}) : (new boolean[] {true,false,true});
-      mLayerRotatable = new boolean[numAxis][];
-      for(int i=0; i<numAxis; i++) mLayerRotatable[i] = tmp;
-      }
+          {{0,1},{3,1},{2,3},{0,2}},
+          {{2,3},{3,1},{0,1},{0,2}},
+          {{1,2},{0,1},{0,3},{2,3}},
+          {{1,2},{2,3},{0,3},{0,1}},
+          {{0,3},{0,2},{1,2},{1,3}},
+          {{1,2},{0,2},{0,3},{1,3}},
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -551,6 +574,7 @@ public class TwistySkewb extends Twisty6
       {
       float[][] STICKERS = new float[][]
           {
+             { -0.5f, 0.25f, 0.25f,  -0.5f, 0.25f, 0.25f  },
              { -0.5f, 0.25f, 0.25f,  -0.5f, 0.25f, 0.25f  },
              { -0.5f, 0.00f, 0.00f,  -0.5f, 0.50f, 0.0f, 0.0f, 0.5f }
           };
@@ -570,12 +594,11 @@ public class TwistySkewb extends Twisty6
         strokes[2]*=mult;
         }
 
-      mStickers = new ObjectSticker[STICKERS.length+1];
+      mStickers = new ObjectSticker[STICKERS.length];
 
-      for(int s=0; s<STICKERS.length+1; s++)
+      for(int s=0; s<STICKERS.length; s++)
         {
-        int index = s<2 ? 0:1;
-        mStickers[s] = new ObjectSticker(STICKERS[index],null,radii[s],strokes[s]);
+        mStickers[s] = new ObjectSticker(STICKERS[s],null,radii[s],strokes[s]);
         }
       }
 
@@ -590,20 +613,6 @@ public class TwistySkewb extends Twisty6
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,2*numLayers[0]-2,TYPE_SPLIT_CORNER,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -649,6 +658,18 @@ public class TwistySkewb extends Twisty6
     return R.string.skew2_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    switch(numLayers[0])
+      {
+      case 2: return 1982;
+      case 3: return 2003;
+      }
+    return 1982;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistySquare.java b/src/main/java/org/distorted/objectlib/objects/TwistySquare.java
index 2e9f082c..58cdd088 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistySquare.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistySquare.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_HEXAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_NOT_SPLIT;
 
 import android.content.res.Resources;
@@ -28,8 +29,6 @@ import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshSquare;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
-import org.distorted.objectlib.main.Movement;
-import org.distorted.objectlib.main.Movement6;
 import org.distorted.objectlib.main.Twisty6;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -51,15 +50,8 @@ abstract class TwistySquare extends Twisty6
       new Static3D(0,-1,0),
     };
 
-  private static final int[][][] ENABLED = new int[][][]
-    {
-      {{0}},{{0}},{{1}},{{1}},{{0,1}},{{0,1}}
-    };
-
   private int[] mBasicAngle;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
-  private Movement mMovement;
   Static4D[] mQuats;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -140,34 +132,45 @@ abstract class TwistySquare extends Twisty6
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      mLayerRotatable = new boolean[][] { {true,false,true}, {true,true}, {true,false,true} };
-      }
+    return new boolean[][] { {true,false,true}, {true,true}, {true,false,true} };
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
 
-  public Static3D[] getRotationAxis()
+  public int getMovementType()
     {
-    return ROT_AXIS;
+    return MOVEMENT_HEXAHEDRON;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public Movement getMovement()
+  public int getMovementSplit()
     {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement6(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_NOT_SPLIT,ENABLED);
-      }
-    return mMovement;
+    return TYPE_NOT_SPLIT;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][] { {{0}},{{0}},{{1}},{{1}},{{0,1}},{{0,1}} };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public Static3D[] getRotationAxis()
+    {
+    return ROT_AXIS;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistySquare1.java b/src/main/java/org/distorted/objectlib/objects/TwistySquare1.java
index 70f93668..4e57cf02 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistySquare1.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistySquare1.java
@@ -302,7 +302,7 @@ public class TwistySquare1 extends TwistySquare
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -382,6 +382,13 @@ public class TwistySquare1 extends TwistySquare
     return R.string.squa1_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 1999;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistySquare2.java b/src/main/java/org/distorted/objectlib/objects/TwistySquare2.java
index c3596920..2da894fc 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistySquare2.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistySquare2.java
@@ -319,7 +319,7 @@ public class TwistySquare2 extends TwistySquare
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 3;
     }
@@ -415,6 +415,13 @@ public class TwistySquare2 extends TwistySquare
     return R.string.squa2_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 1995;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistyUltimate.java b/src/main/java/org/distorted/objectlib/objects/TwistyUltimate.java
index 7573c544..260e9547 100644
--- a/src/main/java/org/distorted/objectlib/objects/TwistyUltimate.java
+++ b/src/main/java/org/distorted/objectlib/objects/TwistyUltimate.java
@@ -19,6 +19,7 @@
 
 package org.distorted.objectlib.objects;
 
+import static org.distorted.objectlib.main.Movement.MOVEMENT_DODECAHEDRON;
 import static org.distorted.objectlib.main.Movement.TYPE_NOT_SPLIT;
 
 import android.content.res.Resources;
@@ -30,7 +31,6 @@ import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import org.distorted.objectlib.R;
-import org.distorted.objectlib.main.Movement;
 import org.distorted.objectlib.main.Movement12;
 import org.distorted.objectlib.main.ObjectControl;
 import org.distorted.objectlib.main.ObjectType;
@@ -59,21 +59,14 @@ public class TwistyUltimate extends Twisty12
            new Static3D( 0,C,-B)
          };
 
-  private static final int[][][] ENABLED = new int[][][]
-    {
-      {{2,3}},{{1,3}},{{1,3}},{{2,3}},{{0,3}},{{0,2}},{{0,2}},{{0,3}},{{1,2}},{{0,1}},{{0,1}},{{1,2}}
-    };
-
   private ScrambleState[] mStates;
   private int[] mBasicAngle;
   private Static4D[] mQuats;
   private float[][] mCuts;
-  private boolean[][] mLayerRotatable;
   private int[][] mFaceMap;
   private float[][] mCenters;
   private int[] mQuatIndex;
   private ObjectSticker[] mStickers;
-  private Movement mMovement;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -374,7 +367,7 @@ public class TwistyUltimate extends Twisty12
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  protected int getSolvedFunctionIndex()
+  public int getSolvedFunctionIndex()
     {
     return 0;
     }
@@ -394,19 +387,49 @@ public class TwistyUltimate extends Twisty12
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void getLayerRotatable(int[] numLayers)
+  public boolean[][] getLayerRotatable(int[] numLayers)
     {
-    if( mLayerRotatable==null )
-      {
-      int numAxis = ROT_AXIS.length;
-      mLayerRotatable = new boolean[numAxis][];
+    int numAxis = ROT_AXIS.length;
+    boolean[][] layerRotatable = new boolean[numAxis][];
 
-      for(int i=0; i<numAxis; i++)
-        {
-        mLayerRotatable[i] = new boolean[numLayers[i]];
-        for(int j=0; j<numLayers[i]; j++) mLayerRotatable[i][j] = true;
-        }
+    for(int i=0; i<numAxis; i++)
+      {
+      layerRotatable[i] = new boolean[numLayers[i]];
+      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
       }
+
+    return layerRotatable;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementType()
+    {
+    return MOVEMENT_DODECAHEDRON;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getMovementSplit()
+    {
+    return TYPE_NOT_SPLIT;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][][] getEnabled()
+    {
+    return new int[][][]
+      {
+        {{2,3}},{{1,3}},{{1,3}},{{2,3}},{{0,3}},{{0,2}},{{0,2}},{{0,3}},{{1,2}},{{0,1}},{{0,1}},{{1,2}}
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[] getDist3D(int[] numLayers)
+    {
+    return null;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -431,20 +454,6 @@ public class TwistyUltimate extends Twisty12
     return ROT_AXIS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public Movement getMovement()
-    {
-    if( mMovement==null )
-      {
-      int[] numLayers = getNumLayers();
-      if( mCuts==null ) getCuts(numLayers);
-      getLayerRotatable(numLayers);
-      mMovement = new Movement12(ROT_AXIS,mCuts,mLayerRotatable,numLayers[0],TYPE_NOT_SPLIT,ENABLED);
-      }
-    return mMovement;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int[] getBasicAngle()
@@ -474,6 +483,13 @@ public class TwistyUltimate extends Twisty12
     return R.string.ulti2_inventor;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention(int[] numLayers)
+    {
+    return 2000;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getComplexity(int[] numLayers)
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 67eb456b..d8ff5751 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -33,34 +33,34 @@
     <string name="bandaged_3plate" translatable="false">3Plate Cube</string>
     <string name="bandaged_evil"   translatable="false">Evil Cube</string>
 
-    <string name="cube2_inventor" translatable="false">Larry Nichols, 1970</string>
-    <string name="cube3_inventor" translatable="false">Ernő Rubik, 1974</string>
-    <string name="cube4_inventor" translatable="false">Péter Sebestény, 1981</string>
-    <string name="cube5_inventor" translatable="false">Udo Krell, 1981</string>
-    <string name="pyra3_inventor" translatable="false">Uwe Meffert, 1970</string>
-    <string name="pyra4_inventor" translatable="false">Katsuhiko Okamoto, 2002</string>
-    <string name="pyra5_inventor" translatable="false">Timur Evbatyrov, 2011</string>
-    <string name="skew2_inventor" translatable="false">Tony Durham, 1982</string>
-    <string name="skew3_inventor" translatable="false">Katsuhiko Okamoto, 2003</string>
-    <string name="diam2_inventor" translatable="false">Uwe Meffert, 1984</string>
-    <string name="diam3_inventor" translatable="false">David Pitcher, 2003</string>
-    <string name="diam4_inventor" translatable="false">Timur Evbatyrov, 2011</string>
-    <string name="redi2_inventor" translatable="false">Oskar van Deventer, 2009</string>
-    <string name="heli3_inventor" translatable="false">Adam G. Cowan, 2006</string>
-    <string name="ivy2_inventor"  translatable="false">Eitan Cher, 2009</string>
-    <string name="rex3_inventor"  translatable="false">Andrew Cormier, 2009</string>
-    <string name="dino3_inventor" translatable="false">Robert Webb, 1985</string>
-    <string name="din43_inventor" translatable="false">Robert Webb, 1985</string>
-    <string name="minx2_inventor" translatable="false">Thomas de Bruin, 2008</string>
-    <string name="minx3_inventor" translatable="false">Ferenc Szlivka, 1982</string>
-    <string name="minx4_inventor" translatable="false">David Gugl, 2010</string>
-    <string name="minx5_inventor" translatable="false">Tyler Fox, 2006</string>
-    <string name="ulti2_inventor" translatable="false">Tony Fisher, 2000</string>
-    <string name="squa1_inventor" translatable="false">Vojtech Kopsky, Harel Hrsel, 1999</string>
-    <string name="squa2_inventor" translatable="false">David Litwin, 1995</string>
-    <string name="jing_inventor"  translatable="false">Tony Fisher, 1991</string>
-    <string name="mirr2_inventor" translatable="false">Thomas de Bruin, 2007</string>
-    <string name="mirr3_inventor" translatable="false">Hidetoshi Takeji, 2006</string>
+    <string name="cube2_inventor" translatable="false">Larry Nichols</string>
+    <string name="cube3_inventor" translatable="false">Ernő Rubik</string>
+    <string name="cube4_inventor" translatable="false">Péter Sebestény</string>
+    <string name="cube5_inventor" translatable="false">Udo Krell</string>
+    <string name="pyra3_inventor" translatable="false">Uwe Meffert</string>
+    <string name="pyra4_inventor" translatable="false">Katsuhiko Okamoto</string>
+    <string name="pyra5_inventor" translatable="false">Timur Evbatyrov</string>
+    <string name="skew2_inventor" translatable="false">Tony Durham</string>
+    <string name="skew3_inventor" translatable="false">Katsuhiko Okamoto</string>
+    <string name="diam2_inventor" translatable="false">Uwe Meffert</string>
+    <string name="diam3_inventor" translatable="false">David Pitcher</string>
+    <string name="diam4_inventor" translatable="false">Timur Evbatyrov</string>
+    <string name="redi2_inventor" translatable="false">Oskar van Deventer</string>
+    <string name="heli3_inventor" translatable="false">Adam G. Cowan</string>
+    <string name="ivy2_inventor"  translatable="false">Eitan Cher</string>
+    <string name="rex3_inventor"  translatable="false">Andrew Cormier</string>
+    <string name="dino3_inventor" translatable="false">Robert Webb</string>
+    <string name="din43_inventor" translatable="false">Robert Webb</string>
+    <string name="minx2_inventor" translatable="false">Thomas de Bruin</string>
+    <string name="minx3_inventor" translatable="false">Ferenc Szlivka</string>
+    <string name="minx4_inventor" translatable="false">David Gugl</string>
+    <string name="minx5_inventor" translatable="false">Tyler Fox</string>
+    <string name="ulti2_inventor" translatable="false">Tony Fisher</string>
+    <string name="squa1_inventor" translatable="false">Vojtech Kopsky, Harel Hrsel</string>
+    <string name="squa2_inventor" translatable="false">David Litwin</string>
+    <string name="jing_inventor"  translatable="false">Tony Fisher</string>
+    <string name="mirr2_inventor" translatable="false">Thomas de Bruin</string>
+    <string name="mirr3_inventor" translatable="false">Hidetoshi Takeji</string>
 
     <string name="bandaged_fused_inventor"  translatable="false">who knows</string>
     <string name="bandaged_2bar_inventor"   translatable="false">who knows</string>
