There is an H \times W grid (H vertical, W horizontal), where each square contains a lowercase English letter. Specifically, the letter in the square at the i-th row and j-th column is equal to the j-th character in the string S_i.

Snuke can apply the following operation to this grid any number of times:

* Choose two different rows and swap them. Or, choose two different columns and swap them.



Snuke wants this grid to be symmetric. That is, for any 1 \leq i \leq H and 1 \leq j \leq W, the letter in the square at the i-th row and j-th column and the letter in the square at the (H + 1 - i)-th row and (W + 1 - j)-th column should be equal.

Determine if Snuke can achieve this objective.

Constraints

* 1 \leq H \leq 12
* 1 \leq W \leq 12
* |S_i| = W
* S_i consists of lowercase English letters.

Input

Input is given from Standard Input in the following format:


H W
S_1
S_2
:
S_H


Output

If Snuke can make the grid symmetric, print `YES`; if he cannot, print `NO`.

Examples

Input

2 3
arc
rac


Output

YES


Input

3 7
atcoder
regular
contest


Output

NO


Input

12 12
bimonigaloaf
faurwlkbleht
dexwimqxzxbb
lxdgyoifcxid
ydxiliocfdgx
nfoabgilamoi
ibxbdqmzxxwe
pqirylfrcrnf
wtehfkllbura
yfrnpflcrirq
wvcclwgiubrk
lkbrwgwuiccv


Output

YES
//TODO
//#include "debug.h"
#include <iostream>
#include <string.h>
#include <limits.h>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;

#define MAXN 12

int n, m;
char g[MAXN][MAXN+1];
char t[MAXN+1];

int input() {
	if (scanf("%d %d", &n, &m) < 0) return 0;
	for (int i=0; i<n; i++)
		scanf("%s", g[i]);
	return 1;
}

void init() {
}

string col_str(int j) {
	for (int i=0; i<n; i++) t[i] = g[i][j];
	t[n] = '\0';
	return string(t);
}

int check() {
	multiset<string> ss;
	for (int j=0; j<m; j++) ss.insert(col_str(j));
	int first = 1;
	while (ss.size()>0) {
		auto p = ss.begin();
		string s = *p, r = s;
		reverse(r.begin(), r.end());
		ss.erase(p);
		auto q = ss.find(r);
		if (q==ss.end()) {
			if (m%2==0) return 0;
			if (!first || r != s) return 0;
			first = 0;
		}
		else ss.erase(q);
	}
	//for (int i=0; i<n; i++) printf("%s\n", g[i]);
	return 1;
}

void swap_str(int i, int j) {
	if (i==j) return;
	strcpy(t, g[i]);
	strcpy(g[i], g[j]);
	strcpy(g[j], t);
}

int srch(int p) {
	if (p==n/2) {
		return check();
	}
	int q = n-1-p;
	for (int i=p+1; i<=q; i++) {
		swap_str(i,q);
		if (srch(p+1)) return 1;
		swap_str(i,q);
	}
	return 0;
}

int solve() {
	if (n%2) {
		int mid = n/2;
		for (int i=0; i<n; i++) {
			swap_str(i,mid);
			if (srch(0)) return 1;
			swap_str(i,mid);
		}
		return 0;
	}
	else return srch(0);
}

void output(int ans) {
	printf("%s\n", ans? "YES":"NO");
}

void cleanup() {
}

int main() {
	//int ca; scanf("%d", &ca);
	while (input()) {
		init();
		output(solve());
		cleanup();
	}
}


