8 10
cwcwcwcwcw
crcrcrcrcr
cwcwcwcwcw
crcrcrcrcr
cwcwcwcwcw
crcrcrcrcr
cwcwcwcwcw
crcrcrcrcr
12 14
?????r??c?????
?????w????cw?w
??????cr????c?
c?????c??????w
c???????????c?
??c?????cw????
????c?c?c?????
c?????????c???
c?????c?????c?
??????????c??w
?r????c??r????
???w?w??c???c?

0000000000
1010101010
0000000000
1010101010
0000000000
1010101010
0000000000
1010101010

#include <bits/stdc++.h>
using namespace std;
bitset<410> b[410][410], d;
int n, m, r, c;
char s[410][410], t[410][410];
int sl[1000010], tot;
struct Trie {
  int Next[500010][26], Fail[500010], cnt[500010];
  vector<int> End[500010];
  int root, L;
  int newnode() {
    for (int i = 0; i < 26; i++) Next[L][i] = -1;
    End[L].clear();
    return L++;
  }
  void init() {
    L = 0;
    root = newnode();
  }
  void Insert(char buf[], int f) {
    int len = strlen(buf);
    int now = root;
    for (int i = 0; i < len; i++) {
      if (Next[now][buf[i] - 'a'] == -1) Next[now][buf[i] - 'a'] = newnode();
      now = Next[now][buf[i] - 'a'];
    }
    End[now].push_back(f + len);
  }
  void build() {
    queue<int> Q;
    Fail[root] = root;
    for (int i = 0; i < 26; i++) {
      if (Next[root][i] == -1)
        Next[root][i] = root;
      else {
        Fail[Next[root][i]] = root;
        Q.push(Next[root][i]);
      }
    }
    while (!Q.empty()) {
      int now = Q.front();
      Q.pop();
      for (int i = 0; i < 26; i++) {
        if (Next[now][i] == -1)
          Next[now][i] = Next[Fail[now]][i];
        else {
          Fail[Next[now][i]] = Next[Fail[now]][i];
          for (int j = 0; j < End[Fail[Next[now][i]]].size(); j++)
            End[Next[now][i]].push_back(End[Fail[Next[now][i]]][j]);
          Q.push(Next[now][i]);
        }
      }
    }
  }
  void query(char buf[], int x, int y) {
    memset(cnt, 0, sizeof(cnt));
    int now = root, res = 0;
    for (int i = 0; i < 2 * m - 1; i++) {
      while (Next[now][buf[i % m] - 'a'] == -1) now = Fail[now];
      now = Next[now][buf[i % m] - 'a'];
      for (int j = 0; j < End[now].size(); j++)
        if (i >= End[now][j] - 1) {
          cnt[i - End[now][j] + 1]++;
        }
    }
    for (int i = 0; i < m; i++) b[x][y][i] = (cnt[i] == tot);
    return;
  }
  void debug() {
    for (int i = 0; i < L; i++) {
      printf("i = %d\n", i);
      printf("next:\n");
      for (int j = 0; j < 26; j++) printf("%c ", j + 'a');
      puts("");
      for (int j = 0; j < 26; j++) printf("%d ", Next[i][j]);
      puts("");
      printf("end: (tot = %d)\n", End[i].size());
      for (int j = 0; j < End[i].size(); j++) printf("%d ", End[i][j]);
      puts("");
      printf("fail: %d\n\n", Fail[i]);
    }
  }
} ac;
int main(void) {
  while (~scanf("%d%d", &n, &m)) {
    for (int i = 0; i < n; i++) scanf("%s", s[i]);
    scanf("%d%d", &r, &c);
    for (int i = 0; i < r; i++) scanf("%s", t[i]);
    for (int j = 0; j < r; j++) {
      tot = 0;
      int flag = 1;
      for (int k = 0; k < c; k++) {
        if (t[j][k] == '?')
          flag = 1, t[j][k] = '\0';
        else if (flag == 1) {
          sl[tot++] = k;
          flag = 0;
        }
      }
      if (tot == 0) {
        for (int i = 0; i < n; i++)
          for (int l = 0; l < m; l++) b[i][j][l] = 1;
        continue;
      }
      ac.init();
      for (int k = 0; k < tot; k++) ac.Insert(t[j] + sl[k], sl[k]);
      ac.build();
      for (int i = 0; i < n; i++) ac.query(s[i], i, j);
    }
    for (int i = 0; i < n; i++) {
      d.set();
      for (int k = 0; k < r; k++) {
        d &= b[(i + k) % n][k];
      }
      for (int j = 0; j < m; j++) printf("%d", d[j] ? 1 : 0);
      puts("");
    }
    puts("");
  }
  return 0;
}
