#include <bits/stdc++.h>   using namespace std;   template <typename T1>   void print_list(const T1& a) {     cerr << a << endl;   }   template <typename T1, typename T2>   void print_list(const T1& a, const T2& b) {     cerr << a <<     << b << endl;   }   template <typename T1, typename T2, typename T3>   void print_list(const T1& a, const T2& b, const T3& c) {     cerr << a <<     << b <<     << c << endl;   }   template <typename T1, typename T2, typename T3, typename T4>   void print_list(const T1& a, const T2& b, const T3& c, const T4& d) {     cerr << a <<     << b <<     << c <<     << d << endl;   }   template <typename T1, typename T2, typename T3, typename T4, typename T5>   void print_list(const T1& a, const T2& b, const T3& c, const T4& d,                   const T5& e) {     cerr << a <<     << b <<     << c <<     << d <<     << e << endl;   }   template <typename T1, typename T2, typename T3, typename T4, typename T5,             typename T6>   void print_list(const T1& a, const T2& b, const T3& c, const T4& d, const T5& e,                   const T6& f) {     cerr << a <<     << b <<     << c <<     << d <<     << e <<     << f << endl;   }   template <typename T1, typename T2, typename T3, typename T4, typename T5,             typename T6, typename T7>   void print_list(const T1& a, const T2& b, const T3& c, const T4& d, const T5& e,                   const T6& f, const T7& g) {     cerr << a <<     << b <<     << c <<     << d <<     << e <<     << f <<              << g << endl;   }   template <typename A, typename B>   ostream& operator<<(ostream& out, const pair<A, B>& pp) {     out <<  (  << pp.first <<  ,  << pp.second <<  ) ;     return out;   }   template <typename A, typename B>   istream& operator<<(istream& in, pair<A, B>& pp) {     cerr <<  A pair wanted  << endl;     in >> pp.first >> pp.second;     return in;   }   template <typename T>   ostream& operator<<(ostream& out, const vector<T>& vect) {     out <<  length =   << vect.size() << endl;     for (int i = 0; i < vect.size(); i++) out << vect[i] <<    ;     out << endl;     return out;   }   template <typename T>   istream& operator>>(istream& in, vector<T>& vect) {     vect.clear();     int n;     cerr <<  A integer of length wanted  << endl;     in >> n;     vect.resize(n);     cerr << n <<   elements wanted  << endl;     for (int i = 0; i < n; i++) in >> vect[i];     return in;   }   template <typename T>   ostream& operator<<(ostream& out, const vector<vector<T> >& vect) {     out <<  row number=  << vect.size() << endl;     for (int i = 0; i < vect.size(); i++) {       out <<  row #  << i <<  : ;       for (int j = 0; j < vect[i].size(); j++) out <<     << vect[i][j];       out << endl;     }     return out;   }   template <typename T>   istream& operator>>(istream& in, vector<vector<T> >& vect) {     vect.clear();     int n, m;     cerr <<  Two integers wnated  << endl;     in >> n >> m;     vect.resize(n);     cerr <<  A matrix   << n <<   X   << m <<   wanted  << endl;     for (int i = 0; i < n; i++) {       vect[i].resize(m);       for (int j = 0; j < m; j++) in >> vect[i][j];     }     return in;   }   template <typename T>   inline void updateMax(T& a, const T& b) {     a = max(a, b);   }   template <typename T>   inline void updateMin(T& a, const T& b) {     a = min(a, b);   }   template <typename T>   inline vector<T> erase(vector<T> table, int ind) {     assert(ind < table.size());     table.erase(table.begin() + ind);     return table;   }   template <typename T>   vector<T> unique(vector<T> table) {     sort(table.begin(), table.end());     return vector<T>(table.begin(), unique(table.begin(), table.end()));   }   template <class T>   vector<T> parse(const string& ss, const char* cut =    ) {     vector<T> re;     for (int j = 0; j < ss.size(); j++) {       string s;       while (j < ss.size() && NULL == strchr(cut, ss[j])) s += ss[j++];       if (!s.empty()) {         T tmp;         istringstream is(s);         is >> tmp;         re.push_back(tmp);       }     }     return re;   }   int countBit(int n) {     int re = 0;     while (n) re++, n ^= ((((n) ^ ((n)-1)) & n));     return re;   }   int MSB(int n) {     if (n == 0) return 0;     while (((((n) ^ ((n)-1)) & n)) != n) n ^= ((((n) ^ ((n)-1)) & n));     return n;   }   void initHash(int n, int hash[]) {     for (int i = 0; i < n; i++) hash[((1) << (i))] = i;   }   void initBcnt(int n, int bcnt[]) {     bcnt[0] = 0;     for (int i = 1; i < ((1) << (n)); i++)       bcnt[i] = bcnt[i ^ ((((i) ^ ((i)-1)) & i))] + 1;   }   template <typename T>   T __gcd(T n, T m, T& a, T& b) {     T a1 = 0, b1 = 1;     a = 1, b = 0;     while (m) {       T c = n / m;       T r = n - m * c;       T t;       t = a;       a = a1;       a1 = t - c * a1;       t = b;       b = b1;       b1 = t - c * b1;       n = m;       m = r;     }     return n;   }   struct Node {     int r, c, d;     int v;     Node(int x, int y, int z, int v1) : r(x), c(y), d(z), v(v1){};     bool operator<(const Node& other) const { return v > other.v; };   };   priority_queue<Node> heap;   const int dir[][2] = {{-1, 0}, {0, 1},  {1, 0},  {0, -1},                         {1, 1},  {1, -1}, {-1, 1}, {-1, -1}};   const char dname[] =  NWSE ;   const string vv[] = { ......... ,  ....O.... ,  ..O...O.. ,  ..O.O.O.. ,                         O.O...O.O ,  O.O.O.O.O ,  O.OO.OO.O };   const string hh[] = { ......... ,  ....O.... ,  O.......O ,  O...O...O ,                         O.O...O.O ,  O.O.O.O.O ,  OOO...OOO };   char grid[2000][2000];   int dom[1000][1000];   long long int col1[1000], col2[1000];   long long int dp[1000];   const long long int mod = 1000000007;   long long int buf[1000];   int main() {     map<string, int> mem;     for (int i = 0; i < 7; i++) {       mem[vv[i]] |= 1;       mem[hh[i]] |= 2;     }     int n, m;     scanf( %d %d , &n, &m);     for (int i = 0; i < 4 * n + 1; i++) {       scanf( %s , grid[i]);     }     for (int i = 0; i < n; i++)       for (int j = 0; j < m; j++) {         int x = 4 * i + 1;         int y = 4 * j + 1;         string s(9,  . );         for (int a = 0; a < 3; a++)           for (int b = 0; b < 3; b++) {             s[a * 3 + b] = grid[x + a][y + b];           }         assert(mem.count(s));         dom[i][j] = mem[s];       }     for (int i = 0; i < m; i++) {       col1[i] = 1 - (n & 1);       for (int j = 1; j < n && col1[i]; j += 2) {         if (0 == (dom[j][i] & 1) || 0 == (dom[j - 1][i] & 1)) {           col1[i]--;           break;         }       }     }     for (int i = 0; i + 1 < m; i++) {       dp[0] = 1;       for (int j = 1; j <= n; j++) {         dp[j] = 0;         if ((dom[j - 1][i] & 2) && (dom[j - 1][i + 1] & 2)) {           dp[j] += dp[j - 1];         }         if (j >= 2 && (dom[j - 1][i] & 1) && (dom[j - 2][i] & 1) &&             (dom[j - 1][i + 1] & 1) && (dom[j - 2][i + 1] & 1)) {           dp[j] += dp[j - 2];         }         dp[j] %= mod;       }       col2[i] = dp[n];     }     dp[0] = 1;     for (int i = 1; i <= m; i++) {       dp[i] = 0;       dp[i] += col1[i - 1] * dp[i - 1];       if (i >= 2) {         dp[i] += (col2[i - 2] + mod - col1[i - 1] * col1[i - 2]) * dp[i - 2];       }       dp[i] %= mod;     }     cout << dp[m] << endl;     return 0;   }