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
//written by libra9z
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i,n) for (int i=0;i<(n);i++)
#define repit(it,a) for (__typeof(a.begin()) it=a.begin();it!=a.end();++it)
#define RET(p,x) return p<<x<<endl,0
#define all(a) (a).begin(),(a).end()
#define reunique(v) v.erase(unique(all(v)),v.end())
#define sz(a) (int)a.size()
#define sqr(x) ((x)*(x))
const int inf=1e9;
const ll lnf=1e18;
const int mod=1e9+7;
ll h,w;
string s[15];
string t[15];
bool ans;
void check()
{
	map <string,ll> cnt;
	rep(j,w)
	{
		string s;
		rep(i,h)
		{
			if (t[i][j]=='@') s+=t[h-1-i][j];
			else s+=t[i][j];
		}
		string t=s;
		reverse(all(t));
		cnt[min(s,t)]++;
	}
	bool flag=false;
	for (auto &p:cnt)
	{
		string s=p.first;
		string t=s;
		reverse(all(t));
		if (p.second%2==0) continue;
		if (s!=t) return;
		if (flag) return;
		flag=true;
	}
	ans=true;
}
void dfs(ll b,ll k)
{
	if (b==0)
	{
		check();
		return;
	}
	ll p=0;
	while (~b>>p&1) p++;
	t[k]=s[p];
	for (ll i=p+1;i<h;i++)
	{
		if (b>>i&1)
		{
			t[h-1-k]=s[i];
			dfs(b^(1<<p)^(1<<i),k+1);
		}
	}
}
int main()
{
	ios_base::sync_with_stdio(0);cin.tie();cout.tie();
	cout<<setprecision(15);
	cin>>h>>w;
	rep(i,h) cin>>s[i];
	if (h&1)
	{
		s[h]=string(w,'@');
		h++;
	}
	dfs((1<<h)-1,0);
	if (ans) cout<<"YES\n";
	else cout<<"NO\n";
	return 0;
}