#include <iostream>
#include <complex>
#include <sstream>
#include <string>
#include <algorithm>
#include <deque>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <vector>
#include <set>
#include <limits>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
#define REP(i, j) for(int i = 0; i < (int)(j); ++i)
#define FOR(i, j, k) for(int i = (int)(j); i < (int)(k); ++i)
#define SORT(v) sort((v).begin(), (v).end())
#define REVERSE(v) reverse((v).begin(), (v).end())
typedef complex<double> P;
const int N = 8;

int H[6][6] = { {1,5,2,3,0,4}, {3,1,0,5,4,2}, {2,1,5,0,4,3}, {4,0,2,3,5,1}, {0,2,4,1,3,5}, {0,3,1,4,2,5} };

enum{TOP, FRONT, RIGHT, LEFT, BACK, BOTTOM};
struct Cube{
  vector<char> d;
  Cube(vector<char> v) { d = v; }
  Cube(string &s){ d = vector<char>(6); REP(i, s.length()) d[i] = s[i]; }
  Cube(){ d = vector<char>(6, '-'); }
  void roll(int dir) {
    vector<char> nx(6);
    for(int i = 0 ; i < 6 ; i++ ) nx[i] = d[H[dir][i]];
    d = nx;
  }
  string to_string(){
    stringstream ss;
    REP(i, 6) ss << d[i];
    return ss.str();
  }
};

bool operator<(const Cube& a, const Cube& b) {
  REP(i, 6) if(a.d[i] != b.d[i]) return a.d[i] < b.d[i];
  return 0;
}

bool ans = false;
int D[12][4] = {
  {0, 1, RIGHT, LEFT},
  {0, 2, FRONT, BACK},
  {0, 4, BOTTOM, TOP},
  {1, 3, FRONT, BACK},
  {1, 5, BOTTOM, TOP},
  {2, 3, RIGHT, LEFT},
  {2, 6, BOTTOM, TOP},
  {3, 7, BOTTOM, TOP},
  {4, 5, RIGHT, LEFT},
  {4, 6, FRONT, BACK},
  {5, 7, FRONT, BACK},
  {6, 7, RIGHT, LEFT}
};

bool check(int n, vector<Cube> &v){
  REP(i, 12){
    int a = D[i][0], b = D[i][1], da = D[i][2], db = D[i][3];
    if(v[a].d[da] == '-' || v[b].d[db] == '-') continue;
    if(toupper(v[a].d[da]) != toupper(v[b].d[db])) return false;
    if((isupper(v[a].d[da]) && isupper(v[b].d[db])) || (islower(v[a].d[da]) && islower(v[b].d[db]))) return false;
  }
  return true;
}

//void dfs(int n, vector<Cube> &v, Cube cs[N], vector<bool> &used, set< vector<Cube> > &closed){
void dfs(int n, vector<Cube> &v, Cube cs[N], vector<bool> &used){
  //REP(i, v.size()) cout <<v[i].to_string() <<", "; cout <<endl;
  if(ans) return ;
  if(n >= N) { ans = true; return ; }
  //if(closed.find(v) != closed.end()) return ;
  //closed.insert(v);

  REP(i, N){
    if(used[i]) continue;
    used[i] = true;

    Cube c = cs[i];
    //v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used, closed);
    //REP(i, 3) { c.roll(4); v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used, closed); }
    v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used);
    REP(i, 3) { c.roll(4); v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used); }
    c.roll(4);

    c.roll(0);
    v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used);
    REP(i, 3) { c.roll(4); v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used); }
    c.roll(4);

    c.roll(0);
    v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used);
    REP(i, 3) { c.roll(4); v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used); }
    c.roll(4);

    c.roll(0);
    v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used);
    REP(i, 3) { c.roll(4); v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used); }
    c.roll(4);

    c.roll(0); c.roll(1);
    v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used);
    REP(i, 3) { c.roll(4); v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used); }
    c.roll(4);

    c.roll(2); c.roll(2);
    v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used);
    REP(i, 3) { c.roll(4); v[n] = c; if(!ans && check(n, v)) dfs(n + 1, v, cs, used); }
    c.roll(4);

    v[n] = Cube();
    used[i] = false;
  }
}

int main() {
  string s;
  while(cin >>s && s != "0"){
    Cube cs[N]; cs[0] = Cube(s);
    FOR(i, 1, N) { cin >>s; cs[i] = Cube(s); }

    ans = false;
    vector<Cube> v(N, Cube());
    vector<bool> used(N, 0);
    //set< vector<Cube> > closed;
    //dfs(0, v, cs, used, closed);
    dfs(0, v, cs, used);
    cout <<(ans ? "YES" : "NO") <<endl;
  }
  return 0;
}