You have a rectangular n × m-cell board. Some cells are already painted some of k colors. You need to paint each uncolored cell one of the k colors so that any path from the upper left square to the lower right one doesn't contain any two cells of the same color. The path can go only along side-adjacent cells and can only go down or right.

Print the number of possible paintings modulo 1000000007 (109 + 7).

Input

The first line contains three integers n, m, k (1 ≤ n, m ≤ 1000, 1 ≤ k ≤ 10). The next n lines contain m integers each — the board. The first of them contains m uppermost cells of the board from the left to the right and the second one contains m cells from the second uppermost row and so on. If a number in a line equals 0, then the corresponding cell isn't painted. Otherwise, this number represents the initial color of the board cell — an integer from 1 to k.

Consider all colors numbered from 1 to k in some manner.

Output

Print the number of possible paintings modulo 1000000007 (109 + 7).

Examples

Input

2 2 4
0 0
0 0


Output

48


Input

2 2 4
1 2
2 1


Output

0


Input

5 6 10
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0


Output

3628800


Input

2 6 10
1 2 3 4 5 6
0 0 0 0 0 0


Output

4096
import java.io.*;

import static java.lang.Math.*;
import java.util.*;
import static java.util.Arrays.fill;
import static java.util.Arrays.sort;

public class Main {
	public static void main(String[] args) {
		if(new File("input.txt").exists())
			try {
				System.setIn(new FileInputStream("input.txt"));
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			}
		new Thread(null, new Runnable() {
			public void run() {
				try {
					new Main().run();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}, "kek", 1 << 23).start();
	}

	BufferedReader in;
	PrintWriter out;
	StringTokenizer st = new StringTokenizer("");
	
	
	void run() throws IOException {
		in = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		Locale.setDefault(Locale.US);
		solve();
		in.close();
		out.close();
	}

	int map[][];
	boolean link[][][][];
	int n, m, k;
	void solve() throws IOException{
		n = nextInt();
		m = nextInt();
		k = nextInt();
		map = new int[n][m];
		if(k < n + m - 1){
			out.println(0);
			return;
		}
		
		for(int i = 0; i < n; i++)
			for(int j = 0; j < m; j++){
				map[i][j] = nextInt();
			}
		
		boolean ok = true;
		link = new boolean[n][m][n][m];
		valid = new boolean[n][m][k + 1];
		for(int i = 0; i < n; i++)
			for(int j = 0; j < m; j++)
				for(int ii = i; ii < n; ii++)
					for(int jj = j; jj < m; jj++){
						link[i][j][ii][jj] = link[ii][jj][i][j] = true;
						
						if(map[i][j] != 0 && map[ii][jj] != 0 && map[ii][jj] == map[i][j] && (i != ii || j != jj)) ok = false;
					}
		if(!ok){
			out.println(0);
			return;
		}
		sz = n * m;
		I = new int[sz];
		J = new int[sz];
		Event evs[] = new Event[sz];
		int pp = 0;
		for(int i = 0; i < n; i++)
			for(int j = 0; j < m; j++)
				evs[pp++] = new Event(i, j);
		sort(evs);
//		System.err.println(Arrays.toString(evs));
		for(int i = 0; i < sz; i++){
			I[i] = evs[i].i;
			J[i] = evs[i].j;
		}
		cntOnGreed = new int[k + 1];
		for(int i = 0; i < n; i++)
			for(int j = 0; j < m; j++)
				cntOnGreed[map[i][j]]++;
		rec(0, 1);
		out.println(answer % 1000000007);
	}
	long answer = 0;
	
	boolean valid[][][];
	int sz;
	
	class Event implements Comparable<Event>{
		int i, j, d;

		public Event(int i, int j) {
			this.i = i;
			this.j = j;
			d = getDist();
		}
		int getDist(){
			return min(i + j, (n + m - i - j - 2)); 
		}
		@Override
		public int compareTo(Event e) {
			if(d != e.d)
				return d - e.d;
			return i != e.i ? (i - e.i) : (j - e.j);
		}
		@Override
		public String toString() {
			return i + " " + j + " ";
		}
		
	}
	
	int cntOnGreed[];
	int I[], J[];
	void rec(int p, long kek){
		if(p == sz){
			answer += kek;
			return;
		}
		int ci = I[p];
		int cj = J[p];
		
		
		if(map[ci][cj] != 0)
			rec(p + 1, kek);
		else {
			boolean v[] = valid[ci][cj];
			fill(v, true);
			for(int ii = 0; ii <= ci; ii++)
				for(int jj = 0; jj <= cj; jj++)
					v[map[ii][jj]] = false;
			

			for(int ii = ci; ii < n; ii++)
				for(int jj = cj; jj < m; jj++)
					v[map[ii][jj]] = false;
			
			for(int color = 1; color <= k; color++){
				if(v[color] && cntOnGreed[color] != 0) {
					map[ci][cj] = color;
					rec(p + 1, kek);
				}
			}
			
			
			int cntFree = 0;
			int ff = 0;
			for(int i = 1; i <= k; i++)
				if(cntOnGreed[i] == 0){
					ff = i;
					cntFree++;
				}
			if(ff != 0){
				map[ci][cj] = ff;
				cntOnGreed[ff]++;
				rec(p + 1, kek * cntFree);
				cntOnGreed[ff]--;
			}
			
			map[ci][cj] = 0;
		}
		
		
	}
	
	
	String nextToken() throws IOException{
		while(!st.hasMoreTokens())
			st = new StringTokenizer(in.readLine());
		return st.nextToken();
	}
	long nextLong() throws IOException{
		return Long.parseLong(nextToken());
	}
	int nextInt() throws IOException{
		return Integer.parseInt(nextToken());
	}
	double nextDouble() throws IOException{
		return Double.parseDouble(nextToken());
	}
}
