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
#pragma GCC optimize(2) //O2优化？

#include<bits/stdc++.h>
#define mp make_pair
#define rep(i,n) for(int i=0;i<n;i++)
#define BINF 0x7fffffff
#define INF 0x3f3f3f3f
#define LINF 9223372036854775807
#define END(s) {cout<<s;return 0;}
#define CON(s) {cout<<s;continue;}
#define BRE(s) {cout<<s;break;}
#define pb push_back
#define All(a) a.begin(),a.end()  //with A in CAPITAL!!!
#define sz(a) (int)a.size()
#define F first
#define S second
#define LOCAL_JUDGE 1 //remember to change
using namespace std;

int row,col;
char in[15][15],c[15];
bool g[15][15];
bool gr[15][15];
string s[15];
int a[15];
bool dfs2(int now,int mask){
	if(now==-1){
		return true;
	}
	int u=col-1-now;
	if(u==now){
		for(int i=0;i<col;i++)
			if(dfs2(now-1,mask|(1<<i))) return true;
	}else{
		int t=0;
		while(mask&(1<<t)) t++;
		mask|=1<<t;
		for(int j=0;j<col;j++)
			if((mask&(1<<j))==0 && g[t][j]){
				if(dfs2(now-1,mask|(1<<j)))
					return true;
			}
	}
	return false;
}
bool dfs(int now,int mask){
	if(now==-1){
		rep(i,col)
			rep(j,col){
				bool flag=true;
				rep(k,row) 
					if(in[a[k]][i]!=in[a[row-k-1]][j]){
						flag=false;
						break;
					}
				g[i][j]=flag;
			}
		return dfs2((col-1)/2,0);
	}
	int u=row-1-now;
	if(now==u){
		rep(i,row){
			a[now]=i;
			if(dfs(now-1,mask|(1<<i))) return true;
		}
	}else{
		int t=0;
		while(mask&(1<<t)) t++;
		a[now]=t;
		mask|=1<<t;
		rep(i,row)
			if((mask&(1<<i))==0 && gr[t][i]){
				a[u]=i;
				if(dfs(now-1,mask|(1<<i)))
					return true;
			}
	}
	return false;
}
int main(){
	//ios::sync_with_stdio(false);
	cin>>row>>col;
	rep(i,row)
		scanf("%s",in[i]);
	rep(i,row){
		rep(j,col) c[j]=in[i][j];
		sort(c,c+col);
		s[i]="";
		rep(j,col) s[i]+=c[j];
	}
	rep(i,row) rep(j,row) gr[i][j]=(s[i]==s[j]);
	if(dfs((row-1)/2,0)) END("YES\n")
	cout<<"NO\n";
	return 0;
}