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
/* Codeforces Template */

import java.io.*;
import java.util.*;

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

public class Main {
	
	static long initTime;
	static final Random rnd = new Random(7777L);
	static boolean writeLog = false;
	
	public static void main(String[] args) throws IOException {
		initTime = System.currentTimeMillis();
		try {
			writeLog = "true".equals(System.getProperty("LOCAL_RUN_7777"));
		} catch (SecurityException e) {}
		new Thread(null, new Runnable() {
			public void run() {
				try {
					try {
						if (new File("input.txt").exists())
							System.setIn(new FileInputStream("input.txt"));
					} catch (SecurityException e) {}
					long prevTime = System.currentTimeMillis();
					new Main().run();
					log("Total time: " + (System.currentTimeMillis() - prevTime) + " ms");
					log("Memory status: " + memoryStatus());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}, "1", 1L << 24).start(); 
	}

	void run() throws IOException {
		in = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		solve();
		out.close();
		in.close();
	}
	
	/*************************************************************** 
	 * Solution
	 **************************************************************/

	final int MOD = 1000000007;
	int answer = 0;
	
	int N;
	int M;
	int K;
	int[][] mat;
	
	int[] mapColor;
	int[] mapCount;
	int[] mapInv;
	
	int[][][] can;
	
	int[][] A;
	
	int[][] tmp;
	
	int mapped = 0;
	
	void solve() throws IOException  {
		
		A = new int [20][20];
		
		for (int n = 0; n < A.length; n++) {
			for (int k = 0; k <= n; k++) {
				A[n][k] = A(n, k);
			}
		}
		
		N = nextInt();
		M = nextInt();
		K = nextInt();
		
		if (N + M - 1 > K) {
			out.println(0);
			return;
		}

		mat = new int [N][M];
		tmp = new int [N][M];
		
		for (int i = 0; i < N; i++)
			for (int j = 0; j < M; j++)
				mat[i][j] = nextInt();
		
	
		mapColor = new int [K + 1];
		mapCount = new int [K + 1];
		mapInv = new int [K];
		fill(mapInv, -1);
		
		can = new int [N][M][K];

		int kk = 0;
		
		for (int i = 0; i < N; i++) {
			if (!color(i, 0, kk++)) {
				out.println(0);
				return;
			}
		}
		
		for (int j = 1; j < M; j++) {
			if (!color(N - 1, j, kk++)) {
				out.println(0);
				return;
			}
		}
		
		rec(N - 2, 1, kk);
		out.println(answer);
	}
	
	int A(int n, int k) {
		int ret = 1;
		for (int i = (n - k + 1); i <= n; i++)
			ret *= i;
		return ret % MOD;
	}

	void rec(int r, int c, int usedColors) {
		if (r < 0 || c >= M) {
			update(usedColors);
			return;
		}
		
		int nr = r;
		int nc = c + 1;
		
		if (nc >= M) {
			nr--;
			nc = 1;
		}
		
		int maxColor = min(K - 1, usedColors);
	
		for (int col = 0; col <= maxColor; col++) {
			if (color(r, c, col)) {
				rec(nr, nc, max(col + 1, usedColors));
				uncolor(r, c, col);
			}
		}
	}

	void update(int usedColors) {
		
//		System.err.println(usedColors);
//		for (int i = 0; i < N; i++)
//			System.err.println(Arrays.toString(tmp[i]));
//		System.err.println(K + " " + usedColors + " " + mapped);
		
		answer += A[K - mapped][usedColors - mapped];
		while (answer >= MOD)
			answer -= MOD;
	}

	boolean color(int i, int j, int c) {
		
		if (can[i][j][c] > 0)
			return false;
		
		int old = mat[i][j];
		
		boolean ret = false;
		
		if (old == 0) {
			ret = true;
		} else if ((mapInv[c] == -1 || mapInv[c] == old) && (mapCount[old] == 0 || mapColor[old] == c)) {
			mapColor[old] = c;
			mapInv[c] = old;
			if (mapCount[old] == 0)
				mapped++;
			mapCount[old]++;
			ret = true;
		}
		
		if (ret) {
			tmp[i][j] = c;
			for (int k = 0; k <= i; k++)
				for (int l = 0; l <= j; l++)
					can[k][l][c]++;
			
			for (int k = i; k < N; k++)
				for (int l = j; l < M; l++)
					can[k][l][c]++;
		}
		
		return ret;
	}
	
	void uncolor(int i, int j, int c) {
		
		int old = mat[i][j];
		if (mapCount[old] > 0) {
			mapCount[old]--;
			if (mapCount[old] == 0) {
				mapInv[c] = -1;
				mapped--;
			}
		}
		
		for (int k = 0; k <= i; k++)
			for (int l = 0; l <= j; l++)
				can[k][l][c]--;
		
		for (int k = i; k < N; k++)
			for (int l = j; l < M; l++)
				can[k][l][c]--;
	}
	

	/*************************************************************** 
	 * Input 
	 **************************************************************/
	BufferedReader in;
	PrintWriter out;
	StringTokenizer st = new StringTokenizer("");
	
	String nextToken() throws IOException {
		while (!st.hasMoreTokens())
			st = new StringTokenizer(in.readLine());
		return st.nextToken();
	}
	
	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}
	
	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}
	
	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}
	
	int[] nextIntArray(int size) throws IOException {
		int[] ret = new int [size];
		for (int i = 0; i < size; i++)
			ret[i] = nextInt();
		return ret;
	}
	
	long[] nextLongArray(int size) throws IOException {
		long[] ret = new long [size];
		for (int i = 0; i < size; i++)
			ret[i] = nextLong();
		return ret;
	}
	
	double[] nextDoubleArray(int size) throws IOException {
		double[] ret = new double [size];
		for (int i = 0; i < size; i++)
			ret[i] = nextDouble();
		return ret;
	}
	
	String nextLine() throws IOException {
		st = new StringTokenizer("");
		return in.readLine();
	}
	
	boolean EOF() throws IOException {
		while (!st.hasMoreTokens()) {
			String s = in.readLine();
			if (s == null)
				return true;
			st = new StringTokenizer(s);
		}
		return false;
	}
	
	/*************************************************************** 
	 * Output 
	 **************************************************************/
	void printRepeat(String s, int count) {
		for (int i = 0; i < count; i++)
			out.print(s);
	}
	
	void printArray(int[] array) {
		if (array == null || array.length == 0)
			return;
		for (int i = 0; i < array.length; i++) {
			if (i > 0) out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}
	
	void printArray(long[] array) {
		if (array == null || array.length == 0)
			return;
		for (int i = 0; i < array.length; i++) {
			if (i > 0) out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}
	
	void printArray(double[] array) {
		if (array == null || array.length == 0)
			return;
		for (int i = 0; i < array.length; i++) {
			if (i > 0) out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}
	
	void printArray(double[] array, String spec) {
		if (array == null || array.length == 0)
			return;
		for (int i = 0; i < array.length; i++) {
			if (i > 0) out.print(' ');
			out.printf(Locale.US, spec, array[i]);
		}
		out.println();
	}
	
	void printArray(Object[] array) {
		if (array == null || array.length == 0)
			return;
		boolean blank = false;
		for (Object x : array) {
			if (blank) out.print(' '); else blank = true;
			out.print(x);
		}
		out.println();
	}
	
	@SuppressWarnings("rawtypes")
	void printCollection(Collection collection) {
		if (collection == null || collection.isEmpty())
			return;
		boolean blank = false;
		for (Object x : collection) {
			if (blank) out.print(' '); else blank = true;
			out.print(x);
		}
		out.println();
	}
	
	/*************************************************************** 
	 * Utility
	 **************************************************************/
	static String memoryStatus() {
		return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory() >> 20) + "/" + (Runtime.getRuntime().totalMemory() >> 20) + " MB";
	}
	
	static void checkMemory() {
		System.err.println(memoryStatus());
	}
	
	static long prevTimeStamp = Long.MIN_VALUE;
	
	static void updateTimer() {
		prevTimeStamp = System.currentTimeMillis();
	}
	
	static long elapsedTime() {
		return (System.currentTimeMillis() - prevTimeStamp);
	}
	
	static void checkTimer() {
		System.err.println(elapsedTime() + " ms");
	}
	
	static void chk(boolean f) {
		if (!f) throw new RuntimeException("Assert failed");
	}
	
	static void chk(boolean f, String format, Object ... args) {
		if (!f) throw new RuntimeException(String.format(format, args));
	}
	
	static void log(String format, Object ... args) {
		if (writeLog) System.err.println(String.format(Locale.US, format, args));
	}
}
