One day little Vasya found mom's pocket book. The book had n names of her friends and unusually enough, each name was exactly m letters long. Let's number the names from 1 to n in the order in which they are written.

As mom wasn't home, Vasya decided to play with names: he chose three integers i, j, k (1 ≤ i < j ≤ n, 1 ≤ k ≤ m), then he took names number i and j and swapped their prefixes of length k. For example, if we take names "CBDAD" and "AABRD" and swap their prefixes with the length of 3, the result will be names "AABAD" and "CBDRD".

You wonder how many different names Vasya can write instead of name number 1, if Vasya is allowed to perform any number of the described actions. As Vasya performs each action, he chooses numbers i, j, k independently from the previous moves and his choice is based entirely on his will. The sought number can be very large, so you should only find it modulo 1000000007 (109 + 7).

Input

The first input line contains two integers n and m (1 ≤ n, m ≤ 100) — the number of names and the length of each name, correspondingly. Then n lines contain names, each name consists of exactly m uppercase Latin letters.

Output

Print the single number — the number of different names that could end up in position number 1 in the pocket book after the applying the procedures described above. Print the number modulo 1000000007 (109 + 7).

Examples

Input

2 3
AAB
BAA


Output

4


Input

4 5
ABABA
BCGDG
AAAAA
YABSA


Output

216

Note

In the first sample Vasya can get the following names in the position number 1: "AAB", "AAA", "BAA" and "BAB".
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;

public class june {

	static Reader r = new Reader();
	static PrintWriter out = new PrintWriter(System.out);

	private static void solve1() throws IOException {

		int n = r.nextInt();
		int arr[] = r.nextIntArray(n);

		int i = 1;
		while (i <= n) {
			for (int j = 0; j < n; j++) {
				if (arr[j] == i) {
					out.print(j + 1 + " ");
				}
			}
			i++;
		}

//		out.print(res);
		out.close();
	}

	static class Point implements Comparable<Point> {
		int x, y;

		public Point(int x, int y) {
			this.x = x;
			this.y = y;
		}

//		@Override
//		public int compareTo(Point o) {
//			if (x == o.x) {
//				return (y - o.y);
//			}
//			return (o.x - x);
//		}

		@Override
		public int compareTo(Point o) {
			if (x == o.x) {
				return (y - o.y);
			}
			return (x - o.x);
		}

	}

	private static void solve2() throws IOException {

		int n = r.nextInt();
		int k = r.nextInt();

		Point arr[] = new Point[n];

		for (int i = 0; i < n; i++) {
			arr[i] = new Point(r.nextInt(), r.nextInt());
		}

		Arrays.sort(arr);
		int ans = 0;

		int prob = arr[k - 1].x, pen = arr[k - 1].y;
		for (int i = 0; i < n; i++) {
			if (arr[i].x == prob && arr[i].y == pen) {
				ans++;
			}
		}

		out.print(ans);
		out.close();

	}

	private static void solve3() throws IOException {

		int n = r.nextInt();

		int arr[] = r.nextIntArray(n);
		Arrays.sort(arr);

		HashSet<Integer> set = new HashSet<Integer>();

		int ans = 0;

		while (n > 0) {
			int cnt = 0;
			for (int i = 0; i < arr.length; i++) {
				if (arr[i] >= cnt && !set.contains(i)) {
					cnt++;
					n--;
					set.add(i);
				}
			}
			ans++;
		}

		out.print(ans);
		out.close();

	}

	private static void solve4() throws IOException {

		int n = r.nextInt();
		int ar[] = r.nextIntArray(n);

		boolean flag = true;
		int cnt1 = 0, cnt2 = 0;

		for (int i = 0; i < n; i++) {
			int rem = ar[i] - 25;
			if (ar[i] == 25) {
				cnt1++;
			} else if (ar[i] == 50) {
				cnt2++;
			}
			if (rem > 0) {
				if (rem == 25) {
					if (cnt1 == 0) {
						flag = false;
						break;
					} else {
						cnt1--;
					}
				} else if (rem == 75) {
					if (cnt1 >= 1 && cnt2 >= 1) {
						cnt1--;
						cnt2--;
					} else if (cnt1 >= 3) {
						cnt1 -= 3;
					} else {
						flag = false;
						break;
					}
				}
			}
		}

		out.print(flag ? "YES" : "NO");
		out.close();

	}

	static class Point_ implements Comparable<Point_> {

		Double x;
		int y;

		public Point_(Double x, int y) {
			this.x = x;
			this.y = y;
		}

		public int compareTo(Point_ o) {
			if (this.x == o.x) {
				return this.y - o.y;
			}
			return Double.compare(x, o.x);
		}

	}

	private static void solve5() throws IOException {

		String s = r.next();

		double x = 0, y = 1;

		Point_ arr[] = new Point_[s.length()];
		for (int i = 0; i < s.length(); i++) {
			arr[i] = new Point_((x + y) / 2, i + 1);
			if (s.charAt(i) == 'l') {
				y = (x + y) / 2;
			} else {
				x = (x + y) / 2;
			}
		}

		Arrays.sort(arr);

		for (int i = 0; i < s.length(); i++) {
			out.print(arr[i].y + "\n");
		}
		out.close();

	}

	private static void solve6() throws IOException {

		int n = r.nextInt();

		HashSet<Integer> x = new HashSet<Integer>();
		HashSet<Integer> y = new HashSet<Integer>();

		for (int i = 0; i < n; i++) {
			x.add(r.nextInt());
			y.add(r.nextInt());
		}

		out.print(Math.min(x.size(), y.size()) - 1);
		out.close();

	}

	private static void solve7() throws IOException {

		int n = r.nextInt();

		int a = r.nextInt();
		int b = r.nextInt();
		int c = r.nextInt();

		int cnt = 0;

		for (int i = 0; i <= 8000; i++) {
			for (int j = 0; j <= 8000; j++) {
				if (n >= a * i + b * j) {
					int k = (n - a * i - b * j) / c;
					if (a * i + b * j + c * k == n)
						cnt = Math.max(cnt, i + j + k);
				}
			}
		}

		out.print(cnt);
		out.close();

	}

	private static void solve8() throws IOException {

		int n = r.nextInt();

		Point arr[] = new Point[n];
		HashSet<Integer> set = new HashSet<Integer>();

		for (int i = 0; i < n; i++) {
			arr[i] = new Point(r.nextInt(), r.nextInt());
		}

		int k = r.nextInt();
		Point tables[] = new Point[k];
		for (int i = 0; i < k; i++) {
			tables[i] = new Point(r.nextInt(), i + 1);
		}
		Arrays.sort(tables);

		int profit = 0, cnt = 0;
		StringBuilder ans = new StringBuilder();

		for (int i = 0; i < k; i++) {
			int max = Integer.MIN_VALUE, idx = -1;
			for (int j = 0; j < n; j++) {
				if (!set.contains(j) && arr[j].x <= tables[i].x) {
					if (arr[j].y > max) {
						max = arr[j].y;
						idx = j;
					}
				}
			}
			if (idx != -1) {
				cnt++;
				profit += max;
				ans.append((idx + 1) + " " + tables[i].y).append("\n");
				set.add(idx);
			}
		}

		out.println(cnt + " " + profit);
		out.print(ans);
		out.close();

	}

	static ArrayList<Integer> graph[];
	static boolean vis[];
	static char arr[];

	static boolean cycleDetection(char ch, int u, int parent) {
		vis[u] = true;
		for (int v : graph[u]) {
			if (arr[v] == ch) {
				if (!vis[v]) {
					if (cycleDetection(ch, v, u)) {
						return true;
					}
				} else if (v != parent) {
					return true;
				}
			} else {
				return false;
			}
		}
		return false;
	}

	private static void solve9() throws IOException {

		int n = r.nextInt();
		int m = r.nextInt();

		char mat[][] = new char[n][m];
		for (int i = 0; i < n; i++) {
			mat[i] = r.next().toCharArray();
		}

		graph = new ArrayList[n * m + 1];
		vis = new boolean[n * m + 1];
		arr = new char[n * m + 1];

		for (int i = 0; i <= n * m; i++) {
			graph[i] = new ArrayList<Integer>();
		}

		boolean flag = false;
		int cnt = 0;

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				cnt++;
				char ch = mat[i][j];
				arr[cnt] = ch;
				if (j + 1 < m && mat[i][j + 1] == ch) {
					graph[cnt].add(cnt + 1);
					graph[cnt + 1].add(cnt);
				}
				if (i + 1 < n && mat[i + 1][j] == ch) {
					graph[cnt].add(cnt + m);
					graph[cnt + m].add(cnt);
				}
			}
		}

		for (int i = 1; i <= n * m; i++) {
//			System.out.println(i + " --> " + graph[i]);
			if (!vis[i]) {
				flag = cycleDetection(arr[i], i, -1);
				if (flag)
					break;
			}
		}

		out.print(flag ? "Yes" : "No");
		out.close();

	}

	private static void solve10() throws IOException {

		int n = r.nextInt();
		int m = r.nextInt();

		String str[] = new String[n];
		for (int i = 0; i < n; i++) {
			str[i] = r.next();
		}

		long ans = 1;

		for (int i = 0; i < m; i++) {
			HashSet<Character> set = new HashSet<>();
			for (int j = 0; j < n; j++) {
				set.add(str[j].charAt(i));
			}
			ans = ((long) ans * set.size()) % ((int) 1e9 + 7);
		}

		out.print(ans);
		out.close();

	}

	public static void main(String[] args) throws IOException {

//		solve1();

//		solve2();

//		solve3();

//		solve4();

//		solve5();

//		solve6();

//		solve7();

//		solve8();

//		solve9();

		solve10();

	}

	static class Reader {

		final private int BUFFER_SIZE = 1 << 12;
		boolean consume = false;
		private byte[] buffer;
		private int bufferPointer, bytesRead;
		private boolean reachedEnd = false;

		public Reader() {
			buffer = new byte[BUFFER_SIZE];
			bufferPointer = 0;
			bytesRead = 0;
		}

		public boolean hasNext() {
			return !reachedEnd;
		}

		private void fillBuffer() throws IOException {
			bytesRead = System.in.read(buffer, bufferPointer = 0, BUFFER_SIZE);
			if (bytesRead == -1) {
				buffer[0] = -1;
				reachedEnd = true;
			}
		}

		private void consumeSpaces() throws IOException {
			while (read() <= ' ' && reachedEnd == false)
				;
			bufferPointer--;
		}

		private byte read() throws IOException {
			if (bufferPointer == bytesRead) {
				fillBuffer();
			}
			return buffer[bufferPointer++];
		}

		public String next() throws IOException {
			StringBuilder sb = new StringBuilder();
			consumeSpaces();
			byte c = read();
			do {
				sb.append((char) c);
			} while ((c = read()) > ' ');
			if (consume) {
				consumeSpaces();
			}
			;
			if (sb.length() == 0) {
				return null;
			}
			return sb.toString();
		}

		public String nextLine() throws IOException {
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			String str = br.readLine();
			return str;
		}

		public int nextInt() throws IOException {
			consumeSpaces();
			int ret = 0;
			byte c = read();
			boolean neg = (c == '-');
			if (neg) {
				c = read();
			}
			do {
				ret = ret * 10 + c - '0';
			} while ((c = read()) >= '0' && c <= '9');
			if (consume) {
				consumeSpaces();
			}
			if (neg) {
				return -ret;
			}
			return ret;
		}

		public long nextLong() throws IOException {
			consumeSpaces();
			long ret = 0;
			byte c = read();
			boolean neg = (c == '-');
			if (neg) {
				c = read();
			}
			do {
				ret = ret * 10L + c - '0';
			} while ((c = read()) >= '0' && c <= '9');
			if (consume) {
				consumeSpaces();
			}
			if (neg) {
				return -ret;
			}
			return ret;
		}

		public double nextDouble() throws IOException {
			consumeSpaces();
			double ret = 0;
			double div = 1;
			byte c = read();
			boolean neg = (c == '-');
			if (neg) {
				c = read();
			}
			do {
				ret = ret * 10 + c - '0';
			} while ((c = read()) >= '0' && c <= '9');
			if (c == '.') {
				while ((c = read()) >= '0' && c <= '9') {
					ret += (c - '0') / (div *= 10);
				}
			}
			if (consume) {
				consumeSpaces();
			}
			if (neg) {
				return -ret;
			}
			return ret;
		}

		public int[] nextIntArray(int n) throws IOException {
			int[] a = new int[n];
			for (int i = 0; i < n; i++) {
				a[i] = nextInt();
			}
			return a;
		}

		public long[] nextLongArray(int n) throws IOException {
			long[] a = new long[n];
			for (int i = 0; i < n; i++) {
				a[i] = nextLong();
			}
			return a;
		}

		public int[][] nextIntMatrix(int n, int m) throws IOException {
			int[][] grid = new int[n][m];
			for (int i = 0; i < n; i++) {
				grid[i] = nextIntArray(m);
			}
			return grid;
		}

		public char[][] nextCharacterMatrix(int n) throws IOException {
			char[][] a = new char[n][];
			for (int i = 0; i < n; i++) {
				a[i] = next().toCharArray();
			}
			return a;
		}

		public void close() throws IOException {
			if (System.in == null) {
				return;
			} else {
				System.in.close();
			}
		}
	}

}