import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/*
 * RubiksCube.java
 *
 * Created on September 18, 2002, 7:24 PM
 */

/**
 *  This class is an abstract representation of a rubiks cube.  It is implemented
 *  by using 6 Face objects.  
 *
 * @author  andrewm
 */
public class RubiksCube
{
    // Constants representing each of the faces
    public static final String FRONT    = "front";
    public static final String BACK     = "back";
    public static final String TOP      = "top";
    public static final String BOTTOM   = "bottom";
    public static final String LEFT     = "left";
    public static final String RIGHT    = "right";
    
    // Output constants
    public static final String SUCCESS = "Yes";
    public static final String FAILURE = "No";
    
    // Input constants
    public static final String START		= "START";
    public static final String END			= "END";
	public static final String END_OF_INPUT = "ENDOFINPUT";
    
    // Face objects
    private Face front;
    private Face back;
    private Face top;
    private Face bottom;
    private Face left;
    private Face right;
    
    /**
     *  Public constructor
     */
    public RubiksCube()
    {
        front = new Face();
        back = new Face();
        top = new Face();
        bottom = new Face();
        left = new Face();
        right = new Face();
    }
    
    /**
     *  Populates the cube from the BufferedReader passed in
     *
     *  @param in BufferedReader used for reading in data
     *  @throws Exception
     */
    public void populate( BufferedReader in ) throws Exception
    {
        // StringTokenizer used for parsing data
        StringTokenizer st = null;
        
        // character arrays used for holding input
        char[] _front = new char[9];
        char[] _back = new char[9];
        char[] _top = new char[9];
        char[] _bottom = new char[9];        
        char[] _left = new char[9];
        char[] _right = new char[9];
        
        try
        {
            // read in the values for the top surface
            for( int i = 0; i < 9; i += 3 )
            {
                st = new StringTokenizer( in.readLine() );
                
                if ( st.countTokens() != 3 )
                {
                    throw new Exception( "invalid number of data values" );
                }
                
                _top[i] = st.nextToken().charAt( 0 );
                _top[i + 1] = st.nextToken().charAt( 0 );
                _top[i + 2] = st.nextToken().charAt( 0 );
            }
            
            top.setData( _top );
            
            // read in the left, front, right and back surfaces
            for( int i = 0; i < 9; i += 3 )
            {
                st = new StringTokenizer( in.readLine() );
                
                if ( st.countTokens() != 12 )
                {
                    throw new Exception( "invalid number of data values" );
                }
                
                _left[i] = st.nextToken().charAt( 0 );
                _left[i + 1] = st.nextToken().charAt( 0 );
                _left[i + 2] = st.nextToken().charAt( 0 );
                
                _front[i] = st.nextToken().charAt( 0 );
                _front[i + 1] = st.nextToken().charAt( 0 );
                _front[i + 2] = st.nextToken().charAt( 0 );
                
                _right[i] = st.nextToken().charAt( 0 );
                _right[i + 1] = st.nextToken().charAt( 0 );
                _right[i + 2] = st.nextToken().charAt( 0 );
                
                _back[i] = st.nextToken().charAt( 0 );
                _back[i + 1] = st.nextToken().charAt( 0 );
                _back[i + 2] = st.nextToken().charAt( 0 );
            }
            
            left.setData( _left );
            front.setData( _front );
            right.setData( _right );
            back.setData( _back );
            
            // read in the values for the bottom surface
            for( int i = 0; i < 9; i += 3 )
            {
                st = new StringTokenizer( in.readLine() );
                
                if ( st.countTokens() != 3 )
                {
                    throw new Exception( "invalid number of data values" );
                }
                
                _bottom[i] = st.nextToken().charAt( 0 );
                _bottom[i + 1] = st.nextToken().charAt( 0 );
                _bottom[i + 2] = st.nextToken().charAt( 0 );
            }
            
            bottom.setData( _bottom );
        }
        catch( Exception e )
        {
            System.out.println( "Error in populate method.  Possibly due to invalid input" );
            throw e;
        }
    }
    
    /**
     *  more - Performs a movement on the rubiks cube
     *
     *  @param command String representation of the command
     *  @throws Exception
     */
    public void move( String command ) throws Exception
    {
        String face = null;
        String direction = null;
        StringTokenizer st = null;
        char[] temp = new char[3];

        st = new StringTokenizer( command );
        
        if ( st.countTokens() == 2 )
        {
            // parse out the face and the direction
            face = st.nextToken();
            direction = st.nextToken();
            
            
            if ( face.equals( FRONT ) )
            {
                if ( direction.equals( RIGHT ) )
                {
                    front.rotate( Face.CLOCKWISE );
                    System.arraycopy( top.getTriplet( Face.BOTTOM ), 0, temp, 0, 3 );
                    top.updateTriplet( left.getTriplet( Face.RIGHT, true ), Face.BOTTOM );
                    left.updateTriplet( bottom.getTriplet( Face.TOP ), Face.RIGHT );
                    bottom.updateTriplet( right.getTriplet( Face.LEFT, true ), Face.TOP );
                    right.updateTriplet( temp, Face.LEFT );            
                }
                else if ( direction.equals( LEFT ) )
                {
                    front.rotate( Face.COUNTERCLOCKWISE );
                    System.arraycopy( top.getTriplet( Face.BOTTOM, true ), 0, temp, 0, 3 );
                    top.updateTriplet( right.getTriplet( Face.LEFT ), Face.BOTTOM );
                    right.updateTriplet( bottom.getTriplet( Face.TOP, true ), Face.LEFT );
                    bottom.updateTriplet( left.getTriplet( Face.RIGHT ), Face.TOP );
                    left.updateTriplet( temp, Face.RIGHT );
                }
                else
                {
                    throw new Exception( "invalid rotation direction" );
                }
            }
            else if ( face.equals( BACK ) )
            {
                if ( direction.equals( RIGHT ) )
                {
                    back.rotate( Face.CLOCKWISE );
                    System.arraycopy( top.getTriplet( Face.TOP, true ), 0, temp, 0, 3 );
                    top.updateTriplet( right.getTriplet( Face.RIGHT ), Face.TOP );
                    right.updateTriplet( bottom.getTriplet( Face.BOTTOM, true ), Face.RIGHT );
                    bottom.updateTriplet( left.getTriplet( Face.LEFT ), Face.BOTTOM );
                    left.updateTriplet( temp, Face.LEFT );                    
                }
                else if ( direction.equals( LEFT ) )
                {
                    back.rotate( Face.COUNTERCLOCKWISE );
                    System.arraycopy( top.getTriplet( Face.TOP ), 0, temp, 0, 3 );
                    top.updateTriplet( left.getTriplet( Face.LEFT, true ), Face.TOP );
                    left.updateTriplet( bottom.getTriplet( Face.BOTTOM ), Face.LEFT );
                    bottom.updateTriplet( right.getTriplet( Face.RIGHT, true ), Face.BOTTOM );
                    right.updateTriplet( temp, Face.RIGHT );
                }
                else
                {
                    throw new Exception( "invalid rotation direction" );
                }
            }
            else if ( face.equals( TOP ) )
            {
                if ( direction.equals( RIGHT ) )
                {
                    top.rotate( Face.CLOCKWISE );
                    System.arraycopy( front.getTriplet( Face.TOP ), 0, temp, 0, 3 );
                    front.updateTriplet( right.getTriplet( Face.TOP ), Face.TOP );
                    right.updateTriplet( back.getTriplet( Face.TOP ), Face.TOP );
                    back.updateTriplet( left.getTriplet( Face.TOP ), Face.TOP );
                    left.updateTriplet( temp, Face.TOP );
                }
                else if ( direction.equals( LEFT ) )
                {
                    top.rotate( Face.COUNTERCLOCKWISE );
                    System.arraycopy( front.getTriplet( Face.TOP ), 0, temp, 0, 3 );
                    front.updateTriplet( left.getTriplet( Face.TOP ), Face.TOP );
                    left.updateTriplet( back.getTriplet( Face.TOP ), Face.TOP );
                    back.updateTriplet( right.getTriplet( Face.TOP ), Face.TOP );
                    right.updateTriplet( temp, Face.TOP );                    
                }
                else
                {
                    throw new Exception( "invalid rotation direction" );
                }
            }
            else if ( face.equals( BOTTOM ) )
            {
                if ( direction.equals( RIGHT ) )
                {
                    bottom.rotate( Face.CLOCKWISE );
                    System.arraycopy( front.getTriplet( Face.BOTTOM ), 0, temp, 0, 3 );
                    front.updateTriplet( left.getTriplet( Face.BOTTOM ), Face.BOTTOM );
                    left.updateTriplet( back.getTriplet( Face.BOTTOM ), Face.BOTTOM );
                    back.updateTriplet( right.getTriplet( Face.BOTTOM ), Face.BOTTOM );
                    right.updateTriplet( temp, Face.BOTTOM );
                }
                else if ( direction.equals( LEFT ) )
                {
                    bottom.rotate( Face.COUNTERCLOCKWISE );
                    System.arraycopy( front.getTriplet( Face.BOTTOM ), 0, temp, 0, 3 );
                    front.updateTriplet( right.getTriplet( Face.BOTTOM ), Face.BOTTOM );
                    right.updateTriplet( back.getTriplet( Face.BOTTOM ), Face.BOTTOM );
                    back.updateTriplet( left.getTriplet( Face.BOTTOM ), Face.BOTTOM );
                    left.updateTriplet( temp, Face.BOTTOM );                    
                }
                else
                {
                    throw new Exception( "invalid rotation direction" );
                }
            }
            else if ( face.equals( LEFT ) )
            {
                if ( direction.equals( RIGHT ) )
                {
                    left.rotate( Face.CLOCKWISE );
                    System.arraycopy( front.getTriplet( Face.LEFT ), 0, temp, 0, 3 );
                    front.updateTriplet( top.getTriplet( Face.LEFT ), Face.LEFT );
                    top.updateTriplet( back.getTriplet( Face.RIGHT, true ), Face.LEFT );
                    back.updateTriplet( bottom.getTriplet( Face.LEFT, true ), Face.RIGHT );
                    bottom.updateTriplet( temp, Face.LEFT );
                }
                else if ( direction.equals( LEFT ) )
                {
                    left.rotate( Face.COUNTERCLOCKWISE );
                    System.arraycopy( front.getTriplet( Face.LEFT ), 0, temp, 0, 3 );
                    front.updateTriplet( bottom.getTriplet( Face.LEFT ), Face.LEFT );
                    bottom.updateTriplet( back.getTriplet( Face.RIGHT, true ), Face.LEFT );
                    back.updateTriplet( top.getTriplet( Face.LEFT, true ), Face.RIGHT );
                    top.updateTriplet( temp, Face.LEFT );                    
                }
                else
                {
                    throw new Exception( "invalid rotation direction" );
                }
            }
            else if ( face.equals( RIGHT ) )
            {
                if ( direction.equals( RIGHT ) )
                {
                    right.rotate( Face.CLOCKWISE );
                    System.arraycopy( front.getTriplet( Face.RIGHT ), 0, temp, 0, 3 );
                    front.updateTriplet( bottom.getTriplet( Face.RIGHT ), Face.RIGHT );
                    bottom.updateTriplet( back.getTriplet( Face.LEFT, true ), Face.RIGHT );
                    back.updateTriplet( top.getTriplet( Face.RIGHT, true ), Face.LEFT );
                    top.updateTriplet( temp, Face.RIGHT );
                }
                else if ( direction.equals( LEFT ) )
                {
                    right.rotate( Face.COUNTERCLOCKWISE );
                    System.arraycopy( front.getTriplet( Face.RIGHT ), 0, temp, 0, 3 );
                    front.updateTriplet( top.getTriplet( Face.RIGHT ), Face.RIGHT );
                    top.updateTriplet( back.getTriplet( Face.LEFT, true ), Face.RIGHT );
                    back.updateTriplet( bottom.getTriplet( Face.RIGHT, true ), Face.LEFT );
                    bottom.updateTriplet( temp, Face.RIGHT );                    
                }
                else
                {
                    throw new Exception( "invalid rotation direction" );
                }
            }  
            else
            {
                throw new Exception( "invalid cube face" );
            }
        }
        else
        {
            throw new Exception( "invalid command: " + command );
        }
    }
        
    /**
     *  Prints out the current representation of the cube
     */
    public void print()
    {
        // print the top face
        System.out.println( "      " + top.getRow( Face.TOP ) );
        System.out.println( "      " + top.getRow( Face.MIDDLE ) );
        System.out.println( "      " + top.getRow( Face.BOTTOM ) );

        // print the first row of the left, front, right and back faces
        System.out.print( left.getRow( Face.TOP ) + " " + front.getRow( Face.TOP ) + " " );
        System.out.println( right.getRow( Face.TOP ) + " " + back.getRow( Face.TOP ) );
        
        // print the second row of the left, front, right and back faces
        System.out.print( left.getRow( Face.MIDDLE ) + " " + front.getRow( Face.MIDDLE ) + " " );
        System.out.println( right.getRow( Face.MIDDLE ) + " " + back.getRow( Face.MIDDLE ) );

        // print the third row of the left, front, right and back faces
        System.out.print( left.getRow( Face.BOTTOM ) + " " + front.getRow( Face.BOTTOM ) + " " );
        System.out.println( right.getRow( Face.BOTTOM ) + " " + back.getRow( Face.BOTTOM ) );
        
        // print the bottom face
        System.out.println( "      " + bottom.getRow( Face.TOP ) );
        System.out.println( "      " + bottom.getRow( Face.MIDDLE ) );
        System.out.println( "      " + bottom.getRow( Face.BOTTOM ) );        
    }
        
    /**
     *  checks to see if the cube is solved
     *
     *  @return boolean Returns true if the cube is solved
     */
    public boolean isSolved()
    {
        return ( ( front.isComplete() ) &&
                 ( back.isComplete() ) &&
                 ( top.isComplete() ) &&
                 ( bottom.isComplete() ) &&
                 ( left.isComplete() ) &&
                 ( right.isComplete() ) );
    }
    
    
    /**
     *  Main method which is run from the command line
     */
    public static void main( String args[] )
    {
        String line = null;
        BufferedReader in = null;
        RubiksCube cube = null;
        
        try
        {
            // open the input stream
            in = new BufferedReader( new InputStreamReader( System.in ) );
            
            // read in a line
            line = in.readLine();
            
            // while there is still more input
            while( ( line != null ) && ( !"".equals( line ) ) )
            {
                // check to see if it starts with the correct start symbol
                if ( line.startsWith( START ) )
                {
                    // create a new cube
                    cube = new RubiksCube();
                    
                    // populate the cube
                    cube.populate( in );
                    
                    // read in a line of data
                    line = in.readLine();
                    
                    // loop through all of the movement commands
                    while( ( line != null ) && ( !"".equals( line ) ) )
                    {
                        // check for the end of the data set
                        if ( line.startsWith( END ) )
                        {
                            break;
                        }
                        
                        // send the command to the move method
                        cube.move( line );
                        
                        // read in the next line
                        line = in.readLine();
                    }
                }
				else if ( line.startsWith( END_OF_INPUT ) )
				{
					break;
				}
                else
                {
                    throw new Exception( "Invalid start symbol.  Expecting " + START );
                }
                
                // check to see if the cube is solved
                if ( cube.isSolved() )
                {
                    System.out.println( SUCCESS );
                }
                else
                {
                    System.out.println( FAILURE );
                }
                
                line = in.readLine();
            }
        }
        catch( Exception e )
        {
            e.printStackTrace();
            System.out.println( e.getMessage() );
        }
    }
}

/**
 *  This class is an abstract representation of a rubiks cube face
 */
class Face
{
    // the actual data of the face
    private char[] data;
    
    // constants used for the direction of rotations
    public static final byte CLOCKWISE        = 0;
    public static final byte COUNTERCLOCKWISE = 1;    
    
    // constants used to signify a row or column of data
    public static final byte TOP    = 0;
    public static final byte MIDDLE = 1;
    public static final byte BOTTOM = 2;
    public static final byte LEFT   = 3;
    public static final byte RIGHT  = 4;

    /**
     *  public constructor
     */
    public Face()
    {
        data = new char[9];
    }

    /**
     *  gets a row or column of data from this face
     *
     *  @param edge A byte representing which edge to get
     *  @return char[] Character array containing the data
     */
    public char[] getTriplet( byte edge )
    {
        return getTriplet( edge, false );
    }
    
    /**
     *  Gets a row or column of data of this face
     *
     *  @param edge A byte representing the edge to get
     *  @param reverse A boolean indicating whether or not the data should be reversed
     *  @return char[] Character array containing the data
     */
    public char[] getTriplet( byte edge, boolean reverse )
    {
        char[] temp = new char[3];
        
        switch( edge )
        {
            case TOP :  if ( reverse )
                        {
                            temp[0] = data[2];
                            temp[1] = data[1];
                            temp[2] = data[0];
                        }
                        else
                        {
                            temp[0] = data[0];
                            temp[1] = data[1];
                            temp[2] = data[2];
                        }
                        break;
            case BOTTOM :   if ( reverse )
                            {
                                temp[0] = data[4];
                                temp[1] = data[5];
                                temp[2] = data[6];
                            }
                            else
                            {
                                temp[0] = data[6];
                                temp[1] = data[5];
                                temp[2] = data[4];
                            }
                            break;
            case LEFT : if ( reverse )
                        {
                            temp[0] = data[6];
                            temp[1] = data[7];
                            temp[2] = data[0];
                        }
                        else
                        {
                            temp[0] = data[0];
                            temp[1] = data[7];
                            temp[2] = data[6];
                        }
                        break;
            case RIGHT :    if ( reverse )
                            {
                                temp[0] = data[4];
                                temp[1] = data[3];
                                temp[2] = data[2];
                            }
                            else
                            {
                                temp[0] = data[2];
                                temp[1] = data[3];
                                temp[2] = data[4];
                            }
                            break;
        }
        
        return temp;
    }
    
    /**
     *  Updates a row or column of the face depending on the edge and direction
     *
     *  @param edge The new data to be put in the row or column
     *  @param byte Byte representing the edge to replace
     */
    public void updateTriplet( char[] edge, byte direction )
    {
        switch( direction )
        {
            case TOP:   data[0] = edge[0];
                        data[1] = edge[1];
                        data[2] = edge[2];
                        break;
            case BOTTOM:    data[6] = edge[0];
                            data[5] = edge[1];
                            data[4] = edge[2];
                            break;
            case LEFT:  data[0] = edge[0];
                        data[7] = edge[1];
                        data[6] = edge[2];
                        break;
            case RIGHT: data[2] = edge[0];
                        data[3] = edge[1];
                        data[4] = edge[2];
                        break;
        }
    }
    
    /**
     *  getRow - returns a string representation of a data row.
     *
     *  @param row A byte representing which row to return
     *  @return String a string representation of a row of data
     */
    public String getRow( byte row )
    {
        String result = "invalid row";
        
        switch( row )
        {
            case TOP:       result = data[0] + " " + data[1] + " " + data[2];
                            break;
            case MIDDLE:    result = data[7] + " " + data[8] + " " + data[3];
                            break;
            case BOTTOM:    result = data[6] + " " + data[5] + " " + data[4];
                            break;
        }
        
        return result;
    }    
    
    
    /**
     *  method to check whether or not this face is complete.
     *
     *  @return boolean Returns true if the face is complete
     */
    public boolean isComplete()
    {
        boolean complete = true;
        char color = data[data.length - 1];
        
        for( int i = 0; i < data.length; i++ )
        {
            if ( data[i] != color )
            {
                complete = false;
                break;
            }
        }
        
        return complete;
    }
    
    /**
     *  rotate - performs a rotation on the data which simulates turning the face
     *           around the center square.
     *
     *  @param byte A byte representing the direction of the rotation
     */
    public void rotate( byte direction )
    {
        char temp;
        
        if ( direction == CLOCKWISE )
        {
            // teporarily store the top left corner
            temp = data[6];
            
            // rotate the corner squares
            for( int i = 6; i >= 2; i -= 2 )
            {
                data[i] = data[i - 2];
            }
            
            // copy the temp into the top right corner
            data[0] = temp;
            
            // temporarily hold the left side edge
            temp = data[7];
            
            // rotate the edge squares
            for( int i = 7; i >= 3; i -= 2 )
            {
                data[i] = data[i - 2];
            }
            
            // copy the temp to the top edge
            data[1] = temp;
        }
        else if ( direction == COUNTERCLOCKWISE )
        {
            // temporarily store the top left corner
            temp = data[0];
            
            // rotate the corner squares
            for( int i = 0; i <= 4; i += 2 )
            {
                data[i] = data[i + 2];
            }
            
            // copy the temp to the bottom left corner
            data[6] = temp;
            
            // temporarily store the top edge
            temp = data[1];
            
            // rotate the edge squares
            for( int i = 1; i <= 5; i += 2 )
            {
                data[i] = data[i + 2];
            }
            
            // copy the temp to the left edge
            data[7] = temp;
        }
    }    
    
    /**
     *  Sets the data array for this face instance
     *
     *  @param data Character array containing the new data
     *  @throws Exception Thrown if the input data isn't the correct length
     */
    public void setData( char[] _data ) throws Exception
    {
        if ( _data.length == 9 )
        {
            data[0] = _data[0];
            data[1] = _data[1];
            data[2] = _data[2];
            data[3] = _data[5];
            data[4] = _data[8];
            data[5] = _data[7];
            data[6] = _data[6];
            data[7] = _data[3];
            data[8] = _data[4];
        }
        else
        {
            throw new Exception( "Invalid input into setData method" );
        }
    }
}